Mercurial > projects > ddmd
annotate dmd/AssertExp.d @ 187:b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
author | Abscissa |
---|---|
date | Tue, 07 Jun 2011 23:37:34 -0400 |
parents | cd48cb899aee |
children |
rev | line source |
---|---|
72 | 1 module dmd.AssertExp; |
2 | |
114 | 3 import dmd.common; |
72 | 4 import dmd.Expression; |
5 import dmd.backend.elem; | |
6 import dmd.UnaExp; | |
7 import dmd.InterState; | |
8 import dmd.OutBuffer; | |
9 import dmd.Loc; | |
10 import dmd.Scope; | |
11 import dmd.InlineCostState; | |
12 import dmd.InlineDoState; | |
13 import dmd.IRState; | |
14 import dmd.HdrGenState; | |
0 | 15 import dmd.InlineScanState; |
16 import dmd.Type; | |
17 import dmd.Global; | |
72 | 18 import dmd.InvariantDeclaration; |
0 | 19 import dmd.TOK; |
174 | 20 import dmd.PREC; |
179 | 21 import dmd.AddrExp; |
22 import dmd.DotVarExp; | |
0 | 23 import dmd.TY; |
24 import dmd.TypeClass; | |
179 | 25 import dmd.GlobalExpressions; |
0 | 26 import dmd.Module; |
27 import dmd.WANT; | |
28 import dmd.FuncDeclaration; | |
29 import dmd.HaltExp; | |
30 import dmd.TypeStruct; | |
31 import dmd.backend.Util; | |
32 import dmd.codegen.Util; | |
33 import dmd.backend.OPER; | |
34 import dmd.backend.TYM; | |
35 import dmd.backend.RTLSYM; | |
36 import dmd.backend.Symbol; | |
37 import dmd.backend.dt_t; | |
38 import dmd.backend.SC; | |
72 | 39 import dmd.backend.FL; |
0 | 40 |
174 | 41 import dmd.expression.Util; |
179 | 42 import dmd.interpret.Util; |
174 | 43 |
0 | 44 import core.stdc.string; |
45 import std.string : toStringz; | |
46 | |
187
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
47 import dmd.DDMDExtensions; |
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
48 |
165
25ede4f66bda
Temporarily disabled GC (again) because phobos fails to compile with it (looks like some ObjSymbols are being falsely collected, see Library.d:666)
korDen
parents:
114
diff
changeset
|
49 //static __gshared Symbol* assertexp_sfilename = null; |
25ede4f66bda
Temporarily disabled GC (again) because phobos fails to compile with it (looks like some ObjSymbols are being falsely collected, see Library.d:666)
korDen
parents:
114
diff
changeset
|
50 //static __gshared string assertexp_name = null; |
25ede4f66bda
Temporarily disabled GC (again) because phobos fails to compile with it (looks like some ObjSymbols are being falsely collected, see Library.d:666)
korDen
parents:
114
diff
changeset
|
51 //static __gshared Module assertexp_mn = null; |
72 | 52 |
0 | 53 class AssertExp : UnaExp |
54 { | |
187
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
55 mixin insertMemberExtension!(typeof(this)); |
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
56 |
0 | 57 Expression msg; |
58 | |
59 this(Loc loc, Expression e, Expression msg = null) | |
60 { | |
178 | 61 register(); |
62 | |
0 | 63 super(loc, TOK.TOKassert, AssertExp.sizeof, e); |
64 this.msg = msg; | |
65 } | |
66 | |
72 | 67 override Expression syntaxCopy() |
0 | 68 { |
72 | 69 AssertExp ae = new AssertExp(loc, e1.syntaxCopy(), |
70 msg ? msg.syntaxCopy() : null); | |
53 | 71 return ae; |
0 | 72 } |
73 | |
72 | 74 override Expression semantic(Scope sc) |
0 | 75 { |
76 version (LOGSEMANTIC) { | |
77 printf("AssertExp.semantic('%s')\n", toChars()); | |
78 } | |
79 UnaExp.semantic(sc); | |
80 e1 = resolveProperties(sc, e1); | |
81 // BUG: see if we can do compile time elimination of the Assert | |
82 e1 = e1.optimize(WANTvalue); | |
83 e1 = e1.checkToBoolean(); | |
84 if (msg) | |
85 { | |
86 msg = msg.semantic(sc); | |
87 msg = resolveProperties(sc, msg); | |
88 msg = msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); | |
89 msg = msg.optimize(WANTvalue); | |
90 } | |
91 if (e1.isBool(false)) | |
92 { | |
93 FuncDeclaration fd = sc.parent.isFuncDeclaration(); | |
94 fd.hasReturnExp |= 4; | |
95 | |
96 if (!global.params.useAssert) | |
174 | 97 { |
0 | 98 Expression e = new HaltExp(loc); |
99 e = e.semantic(sc); | |
100 return e; | |
101 } | |
102 } | |
103 type = Type.tvoid; | |
104 return this; | |
105 } | |
106 | |
72 | 107 override Expression interpret(InterState istate) |
179 | 108 { |
109 Expression e; | |
110 Expression e1; | |
111 | |
112 version (LOG) { | |
113 writef("AssertExp::interpret() %s\n", toChars()); | |
114 } | |
115 if (this.e1.op == TOKaddress) | |
116 { | |
117 // Special case: deal with compiler-inserted assert(&this, "null this") | |
118 AddrExp ade = cast(AddrExp)this.e1; | |
119 if (ade.e1.op == TOKthis && istate.localThis) | |
120 if (ade.e1.op == TOKdotvar | |
121 && (cast(DotVarExp)(istate.localThis)).e1.op == TOKthis) | |
122 return getVarExp(loc, istate, (cast(DotVarExp)(istate.localThis)).var); | |
123 else | |
124 return istate.localThis.interpret(istate); | |
125 } | |
126 if (this.e1.op == TOKthis) | |
127 { | |
128 if (istate.localThis) | |
129 return istate.localThis.interpret(istate); | |
130 } | |
131 e1 = this.e1.interpret(istate); | |
132 if (e1 is EXP_CANT_INTERPRET) | |
133 goto Lcant; | |
134 if (e1.isBool(true)) | |
135 { | |
136 } | |
137 else if (e1.isBool(false)) | |
138 { | |
139 if (msg) | |
140 { | |
141 e = msg.interpret(istate); | |
142 if (e is EXP_CANT_INTERPRET) | |
143 goto Lcant; | |
144 error("%s", e.toChars()); | |
145 } | |
146 else | |
147 error("%s failed", toChars()); | |
148 goto Lcant; | |
149 } | |
150 else | |
151 goto Lcant; | |
152 return e1; | |
153 | |
154 Lcant: | |
155 return EXP_CANT_INTERPRET; | |
0 | 156 } |
157 | |
72 | 158 override bool checkSideEffect(int flag) |
0 | 159 { |
160 return true; | |
161 } | |
162 | |
163 version (DMDV2) { | |
72 | 164 override bool canThrow() |
0 | 165 { |
166 /* assert()s are non-recoverable errors, so functions that | |
167 * use them can be considered "nothrow" | |
168 */ | |
165
25ede4f66bda
Temporarily disabled GC (again) because phobos fails to compile with it (looks like some ObjSymbols are being falsely collected, see Library.d:666)
korDen
parents:
114
diff
changeset
|
169 return false; //(global.params.useAssert != 0); |
0 | 170 } |
171 } | |
72 | 172 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 173 { |
174 | 174 buf.writestring("assert("); |
175 expToCBuffer(buf, hgs, e1, PREC.PREC_assign); | |
176 if (msg) | |
177 { | |
178 buf.writeByte(','); | |
179 expToCBuffer(buf, hgs, msg, PREC_assign); | |
180 } | |
181 buf.writeByte(')'); | |
0 | 182 } |
183 | |
72 | 184 override int inlineCost(InlineCostState* ics) |
0 | 185 { |
186 return 1 + e1.inlineCost(ics) + (msg ? msg.inlineCost(ics) : 0); | |
187 } | |
188 | |
72 | 189 override Expression doInline(InlineDoState ids) |
0 | 190 { |
191 AssertExp ae = cast(AssertExp)copy(); | |
192 | |
193 ae.e1 = e1.doInline(ids); | |
194 if (msg) | |
195 ae.msg = msg.doInline(ids); | |
196 return ae; | |
197 } | |
198 | |
72 | 199 override Expression inlineScan(InlineScanState* iss) |
0 | 200 { |
201 e1 = e1.inlineScan(iss); | |
202 if (msg) | |
203 msg = msg.inlineScan(iss); | |
204 return this; | |
205 } | |
174 | 206 |
0 | 207 static private void* castToVoid(int i) |
208 { | |
209 return cast(void*)i; | |
210 } | |
211 | |
72 | 212 override elem* toElem(IRState* irs) |
0 | 213 { |
214 elem* e; | |
215 elem* ea; | |
216 Type t1 = e1.type.toBasetype(); | |
217 | |
218 //printf("AssertExp.toElem() %s\n", toChars()); | |
219 if (global.params.useAssert) | |
220 { | |
221 e = e1.toElem(irs); | |
222 | |
223 InvariantDeclaration inv = cast(InvariantDeclaration)castToVoid(1); | |
224 | |
225 // If e1 is a class object, call the class invariant on it | |
226 if (global.params.useInvariants && t1.ty == Tclass && | |
227 !(cast(TypeClass)t1).sym.isInterfaceDeclaration()) | |
228 { | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
229 version (POSIX) {///TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS |
0 | 230 e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM__DINVARIANT]), e); |
231 } else { | |
232 e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DINVARIANT]), e); | |
233 } | |
234 } | |
235 // If e1 is a struct object, call the struct invariant on it | |
236 else if (global.params.useInvariants && | |
237 t1.ty == Tpointer && | |
238 t1.nextOf().ty == Tstruct && | |
239 (inv = (cast(TypeStruct)t1.nextOf()).sym.inv) !is null) | |
240 { | |
241 e = callfunc(loc, irs, 1, inv.type.nextOf(), e, e1.type, inv, inv.type, null, null); | |
242 } | |
243 else | |
244 { | |
245 // Construct: (e1 || ModuleAssert(line)) | |
246 Symbol* sassert; | |
247 Module m = irs.blx.module_; | |
248 string mname = m.srcfile.toChars(); | |
249 | |
250 //printf("filename = '%s'\n", loc.filename); | |
251 //printf("module = '%s'\n", m.srcfile.toChars()); | |
252 | |
253 /* If the source file name has changed, probably due | |
254 * to a #line directive. | |
255 */ | |
256 if (loc.filename && (msg || loc.filename != mname)) | |
174 | 257 { |
0 | 258 elem* efilename; |
259 | |
260 /* Cache values. | |
261 */ | |
165
25ede4f66bda
Temporarily disabled GC (again) because phobos fails to compile with it (looks like some ObjSymbols are being falsely collected, see Library.d:666)
korDen
parents:
114
diff
changeset
|
262 Symbol* assertexp_sfilename = null; |
25ede4f66bda
Temporarily disabled GC (again) because phobos fails to compile with it (looks like some ObjSymbols are being falsely collected, see Library.d:666)
korDen
parents:
114
diff
changeset
|
263 string assertexp_name = null; |
25ede4f66bda
Temporarily disabled GC (again) because phobos fails to compile with it (looks like some ObjSymbols are being falsely collected, see Library.d:666)
korDen
parents:
114
diff
changeset
|
264 Module assertexp_mn = null; |
0 | 265 |
266 if (!assertexp_sfilename || loc.filename != assertexp_name || assertexp_mn != m) | |
267 { | |
268 dt_t* dt = null; | |
269 | |
270 string id = loc.filename; | |
271 int len = id.length; | |
272 dtdword(&dt, len); | |
273 dtabytes(&dt,TYnptr, 0, len + 1, toStringz(id)); | |
274 | |
275 assertexp_sfilename = symbol_generate(SCstatic,type_fake(TYdarray)); | |
276 assertexp_sfilename.Sdt = dt; | |
277 assertexp_sfilename.Sfl = FLdata; | |
278 version (ELFOBJ) { | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
279 assertexp_sfilename.Sseg = Segment.CDATA; |
0 | 280 } |
281 version (MACHOBJ) { | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
282 assertexp_sfilename.Sseg = Segment.DATA; |
0 | 283 } |
284 outdata(assertexp_sfilename); | |
285 | |
286 assertexp_mn = m; | |
287 assertexp_name = id; | |
288 } | |
289 | |
290 efilename = el_var(assertexp_sfilename); | |
291 | |
292 if (msg) | |
174 | 293 { |
0 | 294 elem* emsg = msg.toElem(irs); |
295 ea = el_var(rtlsym[RTLSYM_DASSERT_MSG]); | |
296 ea = el_bin(OPcall, TYvoid, ea, el_params(el_long(TYint, loc.linnum), efilename, emsg, null)); | |
297 } | |
298 else | |
299 { | |
300 ea = el_var(rtlsym[RTLSYM_DASSERT]); | |
301 ea = el_bin(OPcall, TYvoid, ea, el_param(el_long(TYint, loc.linnum), efilename)); | |
302 } | |
303 } | |
304 else | |
305 { | |
306 sassert = m.toModuleAssert(); | |
307 ea = el_bin(OPcall,TYvoid,el_var(sassert), | |
308 el_long(TYint, loc.linnum)); | |
309 } | |
310 e = el_bin(OPoror,TYvoid,e,ea); | |
311 } | |
312 } | |
313 else | |
174 | 314 { |
0 | 315 // BUG: should replace assert(0); with a HLT instruction |
316 e = el_long(TYint, 0); | |
317 } | |
318 el_setLoc(e,loc); | |
319 | |
320 return e; | |
321 } | |
322 } | |
323 |