72
|
1 module dmd.DeleteExp;
|
|
2
|
|
3 import dmd.Expression;
|
|
4 import dmd.backend.elem;
|
|
5 import dmd.UnaExp;
|
|
6 import dmd.OutBuffer;
|
|
7 import dmd.Loc;
|
|
8 import dmd.Scope;
|
|
9 import dmd.IRState;
|
0
|
10 import dmd.HdrGenState;
|
|
11 import dmd.Type;
|
|
12 import dmd.IndexExp;
|
|
13 import dmd.Global;
|
|
14 import dmd.VarExp;
|
|
15 import dmd.Identifier;
|
|
16 import dmd.StructDeclaration;
|
|
17 import dmd.Lexer;
|
|
18 import dmd.FuncDeclaration;
|
|
19 import dmd.TypeStruct;
|
|
20 import dmd.CallExp;
|
|
21 import dmd.DotVarExp;
|
|
22 import dmd.DeclarationExp;
|
|
23 import dmd.ExpInitializer;
|
|
24 import dmd.VarDeclaration;
|
|
25 import dmd.TypePointer;
|
|
26 import dmd.ClassDeclaration;
|
|
27 import dmd.TypeClass;
|
72
|
28 import dmd.TY;
|
0
|
29 import dmd.TOK;
|
|
30 import dmd.TypeAArray;
|
|
31 import dmd.TypeSArray;
|
|
32
|
|
33 import dmd.codegen.Util;
|
|
34 import dmd.backend.Util;
|
|
35 import dmd.backend.OPER;
|
|
36 import dmd.backend.RTLSYM;
|
|
37 import dmd.backend.mTY;
|
|
38 import dmd.backend.Symbol;
|
72
|
39 import dmd.backend.TYM;
|
|
40
|
0
|
41 class DeleteExp : UnaExp
|
|
42 {
|
|
43 this(Loc loc, Expression e)
|
|
44 {
|
|
45 super(loc, TOK.TOKdelete, DeleteExp.sizeof, e);
|
|
46 }
|
|
47
|
72
|
48 override Expression semantic(Scope sc)
|
0
|
49 {
|
|
50 Type tb;
|
|
51
|
|
52 UnaExp.semantic(sc);
|
|
53 e1 = resolveProperties(sc, e1);
|
|
54 e1 = e1.toLvalue(sc, null);
|
|
55 type = Type.tvoid;
|
|
56
|
|
57 tb = e1.type.toBasetype();
|
|
58 switch (tb.ty)
|
|
59 {
|
|
60 case Tclass:
|
|
61 {
|
|
62 TypeClass tc = cast(TypeClass)tb;
|
|
63 ClassDeclaration cd = tc.sym;
|
|
64
|
|
65 if (cd.isCOMinterface())
|
|
66 { /* Because COM classes are deleted by IUnknown.Release()
|
|
67 */
|
|
68 error("cannot delete instance of COM interface %s", cd.toChars());
|
|
69 }
|
|
70 break;
|
|
71 }
|
|
72 case Tpointer:
|
|
73 tb = (cast(TypePointer)tb).next.toBasetype();
|
|
74 if (tb.ty == Tstruct)
|
|
75 {
|
|
76 TypeStruct ts = cast(TypeStruct)tb;
|
|
77 StructDeclaration sd = ts.sym;
|
|
78 FuncDeclaration f = sd.aggDelete;
|
|
79 FuncDeclaration fd = sd.dtor;
|
|
80
|
|
81 if (!f && !fd)
|
|
82 break;
|
|
83
|
|
84 /* Construct:
|
|
85 * ea = copy e1 to a tmp to do side effects only once
|
|
86 * eb = call destructor
|
|
87 * ec = call deallocator
|
|
88 */
|
|
89 Expression ea = null;
|
|
90 Expression eb = null;
|
|
91 Expression ec = null;
|
|
92 VarDeclaration v;
|
|
93
|
|
94 if (fd && f)
|
|
95 {
|
|
96 Identifier id = Lexer.idPool("__tmp");
|
|
97 v = new VarDeclaration(loc, e1.type, id, new ExpInitializer(loc, e1));
|
|
98 v.semantic(sc);
|
|
99 v.parent = sc.parent;
|
|
100 ea = new DeclarationExp(loc, v);
|
|
101 ea.type = v.type;
|
|
102 }
|
|
103
|
|
104 if (fd)
|
|
105 {
|
|
106 Expression e = ea ? new VarExp(loc, v) : e1;
|
|
107 e = new DotVarExp(Loc(0), e, fd, 0);
|
|
108 eb = new CallExp(loc, e);
|
|
109 eb = eb.semantic(sc);
|
|
110 }
|
|
111
|
|
112 if (f)
|
|
113 {
|
|
114 Type tpv = Type.tvoid.pointerTo();
|
|
115 Expression e = ea ? new VarExp(loc, v) : e1.castTo(sc, tpv);
|
|
116 e = new CallExp(loc, new VarExp(loc, f), e);
|
|
117 ec = e.semantic(sc);
|
|
118 }
|
|
119 ea = combine(ea, eb);
|
|
120 ea = combine(ea, ec);
|
|
121 assert(ea);
|
|
122 return ea;
|
|
123 }
|
|
124 break;
|
|
125
|
|
126 case Tarray:
|
|
127 /* BUG: look for deleting arrays of structs with dtors.
|
|
128 */
|
|
129 break;
|
|
130
|
|
131 default:
|
|
132 if (e1.op == TOKindex)
|
|
133 {
|
|
134 IndexExp ae = cast(IndexExp)e1;
|
|
135 Type tb1 = ae.e1.type.toBasetype();
|
|
136 if (tb1.ty == Taarray)
|
|
137 break;
|
|
138 }
|
|
139 error("cannot delete type %s", e1.type.toChars());
|
|
140 break;
|
|
141 }
|
|
142
|
|
143 if (e1.op == TOKindex)
|
|
144 {
|
|
145 IndexExp ae = cast(IndexExp)e1;
|
|
146 Type tb1 = ae.e1.type.toBasetype();
|
|
147 if (tb1.ty == Taarray)
|
|
148 {
|
|
149 if (!global.params.useDeprecated)
|
|
150 error("delete aa[key] deprecated, use aa.remove(key)");
|
|
151 }
|
|
152 }
|
|
153
|
|
154 return this;
|
|
155 }
|
|
156
|
72
|
157 override Expression checkToBoolean()
|
0
|
158 {
|
|
159 assert(false);
|
|
160 }
|
|
161
|
72
|
162 override bool checkSideEffect(int flag)
|
0
|
163 {
|
|
164 return true;
|
|
165 }
|
|
166
|
72
|
167 override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
0
|
168 {
|
|
169 assert(false);
|
|
170 }
|
|
171
|
72
|
172 override elem* toElem(IRState* irs)
|
0
|
173 {
|
|
174 elem* e;
|
|
175 int rtl;
|
|
176 Type tb;
|
|
177
|
|
178 //printf("DeleteExp.toElem()\n");
|
|
179 if (e1.op == TOKindex)
|
|
180 {
|
|
181 IndexExp ae = cast(IndexExp)e1;
|
|
182 tb = ae.e1.type.toBasetype();
|
|
183 if (tb.ty == Taarray)
|
|
184 {
|
|
185 TypeAArray taa = cast(TypeAArray)tb;
|
|
186 elem* ea = ae.e1.toElem(irs);
|
|
187 elem* ekey = ae.e2.toElem(irs);
|
|
188 elem* ep;
|
|
189 elem* keyti;
|
|
190
|
|
191 if (tybasic(ekey.Ety) == TYstruct)
|
|
192 {
|
|
193 ekey = el_una(OPstrpar, TYstruct, ekey);
|
|
194 ekey.Enumbytes = ekey.E1.Enumbytes;
|
|
195 assert(ekey.Enumbytes);
|
|
196 }
|
|
197
|
|
198 Symbol *s = taa.aaGetSymbol("Del", 0);
|
|
199 keyti = taa.index.getInternalTypeInfo(null).toElem(irs);
|
|
200 ep = el_params(ekey, keyti, ea, null);
|
|
201 e = el_bin(OPcall, TYnptr, el_var(s), ep);
|
|
202 goto Lret;
|
|
203 }
|
|
204 }
|
|
205 //e1.type.print();
|
|
206 e = e1.toElem(irs);
|
|
207 tb = e1.type.toBasetype();
|
|
208 switch (tb.ty)
|
|
209 {
|
|
210 case Tarray:
|
|
211 {
|
|
212 e = addressElem(e, e1.type);
|
|
213 rtl = RTLSYM_DELARRAYT;
|
|
214
|
|
215 /* See if we need to run destructors on the array contents
|
|
216 */
|
|
217 elem *et = null;
|
|
218 Type tv = tb.nextOf().toBasetype();
|
|
219 while (tv.ty == Tsarray)
|
|
220 {
|
|
221 TypeSArray ta = cast(TypeSArray)tv;
|
|
222 tv = tv.nextOf().toBasetype();
|
|
223 }
|
|
224 if (tv.ty == Tstruct)
|
|
225 {
|
|
226 TypeStruct ts = cast(TypeStruct)tv;
|
|
227 StructDeclaration sd = ts.sym;
|
|
228 if (sd.dtor)
|
|
229 et = tb.nextOf().getTypeInfo(null).toElem(irs);
|
|
230 }
|
|
231 if (!et) // if no destructors needed
|
|
232 et = el_long(TYnptr, 0); // pass null for TypeInfo
|
|
233 e = el_params(et, e, null);
|
|
234 // call _d_delarray_t(e, et);
|
|
235 e = el_bin(OPcall, TYvoid, el_var(rtlsym[rtl]), e);
|
|
236 goto Lret;
|
|
237 }
|
|
238 case Tclass:
|
|
239 if (e1.op == TOKvar)
|
|
240 {
|
|
241 VarExp ve = cast(VarExp)e1;
|
|
242 if (ve.var.isVarDeclaration() &&
|
|
243 ve.var.isVarDeclaration().onstack)
|
|
244 {
|
|
245 rtl = RTLSYM_CALLFINALIZER;
|
|
246 if (tb.isClassHandle().isInterfaceDeclaration())
|
|
247 rtl = RTLSYM_CALLINTERFACEFINALIZER;
|
|
248 break;
|
|
249 }
|
|
250 }
|
|
251 e = addressElem(e, e1.type);
|
|
252 rtl = RTLSYM_DELCLASS;
|
|
253 if (tb.isClassHandle().isInterfaceDeclaration())
|
|
254 rtl = RTLSYM_DELINTERFACE;
|
|
255 break;
|
|
256
|
|
257 case Tpointer:
|
|
258 e = addressElem(e, e1.type);
|
|
259 rtl = RTLSYM_DELMEMORY;
|
|
260 break;
|
|
261
|
|
262 default:
|
|
263 assert(0);
|
|
264 break;
|
|
265 }
|
|
266 e = el_bin(OPcall, TYvoid, el_var(rtlsym[rtl]), e);
|
|
267
|
|
268 Lret:
|
|
269 el_setLoc(e,loc);
|
|
270 return e;
|
|
271 }
|
|
272 }
|
|
273
|