@@ -919,3 +919,236 @@ extern (C) private pure @system @nogc nothrow
919919
920920 pragma (mangle, " free" ) void fakePureFree(void * ptr);
921921}
922+
923+ extern (C ) private @system nothrow @nogc
924+ {
925+ pragma (mangle, " _d_delinterface" ) void _d_delinterface(void ** );
926+ pragma (mangle, " _d_delclass" ) void _d_delclass(Object * );
927+ pragma (mangle, " _d_delstruct" ) void _d_delstruct(void ** , TypeInfo_Struct );
928+ pragma (mangle, " _d_delmemory" ) void _d_delmemory(void ** );
929+ pragma (mangle, " _d_delarray_t" ) void _d_delarray_t(void ** , TypeInfo_Struct );
930+ }
931+
932+ /**
933+ Destroys and then deallocates an object.
934+
935+ In detail, `__delete(x)` returns with no effect if `x` is `null`. Otherwise, it
936+ performs the following actions in sequence:
937+ $(UL
938+ $(LI
939+ Calls the destructor `~this()` for the object referred to by `x`
940+ (if `x` is a class or interface reference) or
941+ for the object pointed to by `x` (if `x` is a pointer to a `struct`).
942+ Arrays of structs call the destructor, if defined, for each element in the array.
943+ If no destructor is defined, this step has no effect.
944+ )
945+ $(LI
946+ Frees the memory allocated for `x`. If `x` is a reference to a class
947+ or interface, the memory allocated for the underlying instance is freed. If `x` is
948+ a pointer, the memory allocated for the pointed-to object is freed. If `x` is a
949+ built-in array, the memory allocated for the array is freed.
950+ If `x` does not refer to memory previously allocated with `new` (or the lower-level
951+ equivalents in the GC API), the behavior is undefined.
952+ )
953+ $(LI
954+ Lastly, `x` is set to `null`. Any attempt to read or write the freed memory via
955+ other references will result in undefined behavior.
956+ )
957+ )
958+
959+ Note: Users should prefer $(REF destroy, object)` to explicitly finalize objects,
960+ and only resort to $(REF __delete, core,memory) when $(REF destroy, object)
961+ wouldn't be a feasible option.
962+
963+ Params:
964+ x = aggregate object that should be destroyed
965+
966+ See_Also: $(REF destroy, object), $(REF free, core,GC)
967+
968+ History:
969+
970+ The `delete` keyword allowed to free GC-allocated memory.
971+ As this is inherently not `@safe`, it has been deprecated.
972+ This function has been added to provide an easy transition from `delete`.
973+ It performs the same functionality as the former `delete` keyword.
974+ */
975+ void __delete (T)(ref T x) @system
976+ {
977+ static void _destructRecurse (S)(ref S s)
978+ if (is (S == struct ))
979+ {
980+ static if (__traits(hasMember, S, " __xdtor" ) &&
981+ // Bugzilla 14746: Check that it's the exact member of S.
982+ __traits (isSame , S, __traits(parent, s.__xdtor)))
983+ s.__xdtor();
984+ }
985+
986+ // See also: https://github.com/dlang/dmd/blob/v2.078.0/src/dmd/e2ir.d#L3886
987+ static if (is (T == interface ))
988+ {
989+ .object.destroy (x);
990+ }
991+ else static if (is (T == class ))
992+ {
993+ .object.destroy (x);
994+ }
995+ else static if (is (T == U* , U))
996+ {
997+ static if (is (U == struct ))
998+ _destructRecurse(* x);
999+ }
1000+ else static if (is (T : E[], E))
1001+ {
1002+ static if (is (E == struct ))
1003+ {
1004+ foreach (ref e; x)
1005+ _destructRecurse(e);
1006+ }
1007+ }
1008+ else
1009+ {
1010+ static assert (0 , " It is not possible to delete: `" ~ T.stringof ~ " `" );
1011+ }
1012+
1013+ static if (is (T == interface ) || is (T == class ))
1014+ {
1015+ GC .free(cast (void * ) x);
1016+ x = null ;
1017+ }
1018+ else static if (is (T == U2 * , U2 ) || is (T : E2 [], E2 ))
1019+ {
1020+ GC .free(&x);
1021+ x = null ;
1022+ }
1023+ }
1024+
1025+ // / Deleting classes
1026+ unittest
1027+ {
1028+ bool dtorCalled;
1029+ class B
1030+ {
1031+ int test;
1032+ ~this ()
1033+ {
1034+ dtorCalled = true ;
1035+ }
1036+ }
1037+ B b = new B();
1038+ B a = b;
1039+ b.test = 10 ;
1040+
1041+ assert (GC .addrOf(cast (void * ) b) != null );
1042+ __delete(b);
1043+ assert (b is null );
1044+ assert (dtorCalled);
1045+ assert (GC .addrOf(cast (void * ) b) == null );
1046+ // but be careful, a still points to it
1047+ assert (a ! is null );
1048+ assert (GC .addrOf(cast (void * ) a) ! is null );
1049+ }
1050+
1051+ // / Deleting interfaces
1052+ unittest
1053+ {
1054+ bool dtorCalled;
1055+ interface A
1056+ {
1057+ int quack ();
1058+ }
1059+ class B : A
1060+ {
1061+ int a;
1062+ int quack ()
1063+ {
1064+ a++ ;
1065+ return a;
1066+ }
1067+ ~this ()
1068+ {
1069+ dtorCalled = true ;
1070+ }
1071+ }
1072+ A a = new B();
1073+ a.quack();
1074+
1075+ assert (GC .addrOf(cast (void * ) a) != null );
1076+ __delete(a);
1077+ assert (a is null );
1078+ assert (dtorCalled);
1079+ assert (GC .addrOf(cast (void * ) a) == null );
1080+ }
1081+
1082+ // / Deleting structs
1083+ unittest
1084+ {
1085+ bool dtorCalled;
1086+ struct A
1087+ {
1088+ string test;
1089+ ~this ()
1090+ {
1091+ dtorCalled = true ;
1092+ }
1093+ }
1094+ auto a = new A(" foo" );
1095+
1096+ assert (GC .addrOf(cast (void * ) a) != null );
1097+ __delete(a);
1098+ assert (a is null );
1099+ assert (dtorCalled);
1100+ assert (GC .addrOf(cast (void * ) a) == null );
1101+ }
1102+
1103+ // / Deleting arrays
1104+ unittest
1105+ {
1106+ int [] a = [1 , 2 , 3 ];
1107+ auto b = a;
1108+
1109+ assert (GC .addrOf(b.ptr) != null );
1110+ __delete(b);
1111+ assert (b is null );
1112+ assert (GC .addrOf(b.ptr) == null );
1113+ // but be careful, a still points to it
1114+ assert (a ! is null );
1115+ assert (GC .addrOf(a.ptr) ! is null );
1116+ }
1117+
1118+ // / Deleting arrays of structs
1119+ unittest
1120+ {
1121+ int dtorCalled;
1122+ struct A
1123+ {
1124+ int a;
1125+ ~this ()
1126+ {
1127+ dtorCalled++ ;
1128+ }
1129+ }
1130+ auto arr = [A(1 ), A(2 ), A(3 )];
1131+
1132+ assert (GC .addrOf(arr.ptr) != null );
1133+ __delete(arr);
1134+ assert (dtorCalled == 3 );
1135+ assert (GC .addrOf(arr.ptr) == null );
1136+ }
1137+
1138+ // Deleting raw memory
1139+ unittest
1140+ {
1141+ import core.memory : GC ;
1142+ auto a = GC .malloc(5 );
1143+ assert (GC .addrOf(cast (void * ) a) != null );
1144+ __delete(a);
1145+ assert (a is null );
1146+ assert (GC .addrOf(cast (void * ) a) == null );
1147+ }
1148+
1149+ // __delete returns with no effect if x is null
1150+ unittest
1151+ {
1152+ Object x = null ;
1153+ __delete(x);
1154+ }
0 commit comments