@@ -153,21 +153,31 @@ mixin template Signal(T1...)
153153 */
154154 final void disconnect (slot_t slot)
155155 {
156- debug (signal) writefln(" Signal.disconnect(slot)" );
156+ size_t disconnectedSlots = 0 ;
157+ size_t instancePreviousSlots = 0 ;
158+
157159 for (size_t i = 0 ; i < slots_idx; )
158160 {
159- if (slots[i] == slot)
160- { slots_idx-- ;
161+ if (slots[i].ptr == slot.ptr &&
162+ ++ instancePreviousSlots &&
163+ slots[i] == slot)
164+ {
165+ slots_idx-- ;
166+ disconnectedSlots++ ;
161167 slots[i] = slots[slots_idx];
162168 slots[slots_idx] = null ; // not strictly necessary
163-
164- Object o = _d_toObject(slot.ptr);
165- rt_detachDisposeEvent(o, &unhook);
166169 }
167170 else
168171 i++ ;
169172 }
170- }
173+
174+ // detach object from dispose event if all its slots have been removed
175+ if (instancePreviousSlots == disconnectedSlots)
176+ {
177+ Object o = _d_toObject(slot.ptr);
178+ rt_detachDisposeEvent(o, &unhook);
179+ }
180+ }
171181
172182 /* **
173183 * Special function called when o is destroyed.
@@ -555,6 +565,34 @@ void linkin() { }
555565 a.value6 = 46 ;
556566}
557567
568+ // Triggers bug from issue 15341
569+ unittest
570+ {
571+ class Observer
572+ {
573+ void watch () { }
574+ void watch2 () { }
575+ }
576+
577+ class Bar
578+ {
579+ mixin Signal ! ();
580+ }
581+
582+ auto a = new Bar ;
583+ auto o = new Observer ;
584+
585+ // Connect both observer methods for the same instance
586+ a.connect(&o.watch);
587+ a.connect(&o.watch2); // not connecting watch2() or disconnecting it manually fixes the issue
588+
589+ // Disconnect a single method of the two
590+ a.disconnect(&o.watch); // NOT disconnecting watch() fixes the issue
591+
592+ destroy (o); // destroying o should automatically call unhook and disconnect the slot for watch2
593+ a.emit(); // should not raise segfault since &o.watch2 is no longer connected
594+ }
595+
558596version (none ) // Disabled because of dmd @@@BUG5028@@@
559597@system unittest
560598{
0 commit comments