0
|
1 module dmd.AssertExp;
|
|
2
|
|
3 import dmd.Expression;
|
|
4 import dmd.backend.elem;
|
|
5 import dmd.UnaExp;
|
|
6 import dmd.InterState;
|
|
7 import dmd.OutBuffer;
|
|
8 import dmd.Loc;
|
|
9 import dmd.Scope;
|
|
10 import dmd.InlineCostState;
|
|
11 import dmd.InlineDoState;
|
|
12 import dmd.IRState;
|
|
13 import dmd.HdrGenState;
|
|
14 import dmd.InlineScanState;
|
|
15 import dmd.Type;
|
|
16 import dmd.Global;
|
|
17 import dmd.InvariantDeclaration;
|
|
18 import dmd.TOK;
|
|
19 import dmd.TY;
|
|
20 import dmd.TypeClass;
|
|
21 import dmd.Module;
|
|
22 import dmd.WANT;
|
|
23 import dmd.FuncDeclaration;
|
|
24 import dmd.HaltExp;
|
|
25 import dmd.TypeStruct;
|
|
26 import dmd.backend.Util;
|
|
27 import dmd.codegen.Util;
|
|
28 import dmd.backend.OPER;
|
|
29 import dmd.backend.TYM;
|
|
30 import dmd.backend.RTLSYM;
|
|
31 import dmd.backend.Symbol;
|
|
32 import dmd.backend.dt_t;
|
|
33 import dmd.backend.SC;
|
|
34 import dmd.backend.FL;
|
|
35
|
|
36 import core.stdc.string;
|
|
37 import std.string : toStringz;
|
|
38
|
|
39 static __gshared Symbol* assertexp_sfilename = null;
|
|
40 static __gshared string assertexp_name = null;
|
|
41 static __gshared Module assertexp_mn = null;
|
|
42
|
|
43 class AssertExp : UnaExp
|
|
44 {
|
|
45 Expression msg;
|
|
46
|
|
47 this(Loc loc, Expression e, Expression msg = null)
|
|
48 {
|
|
49 super(loc, TOK.TOKassert, AssertExp.sizeof, e);
|
|
50 this.msg = msg;
|
|
51 }
|
|
52
|
|
53 Expression syntaxCopy()
|
|
54 {
|
|
55 assert(false);
|
|
56 }
|
|
57
|
|
58 Expression semantic(Scope sc)
|
|
59 {
|
|
60 version (LOGSEMANTIC) {
|
|
61 printf("AssertExp.semantic('%s')\n", toChars());
|
|
62 }
|
|
63 UnaExp.semantic(sc);
|
|
64 e1 = resolveProperties(sc, e1);
|
|
65 // BUG: see if we can do compile time elimination of the Assert
|
|
66 e1 = e1.optimize(WANTvalue);
|
|
67 e1 = e1.checkToBoolean();
|
|
68 if (msg)
|
|
69 {
|
|
70 msg = msg.semantic(sc);
|
|
71 msg = resolveProperties(sc, msg);
|
|
72 msg = msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
|
|
73 msg = msg.optimize(WANTvalue);
|
|
74 }
|
|
75 if (e1.isBool(false))
|
|
76 {
|
|
77 FuncDeclaration fd = sc.parent.isFuncDeclaration();
|
|
78 fd.hasReturnExp |= 4;
|
|
79
|
|
80 if (!global.params.useAssert)
|
|
81 {
|
|
82 Expression e = new HaltExp(loc);
|
|
83 e = e.semantic(sc);
|
|
84 return e;
|
|
85 }
|
|
86 }
|
|
87 type = Type.tvoid;
|
|
88 return this;
|
|
89 }
|
|
90
|
|
91 Expression interpret(InterState* istate)
|
|
92 {
|
|
93 assert(false);
|
|
94 }
|
|
95
|
|
96 bool checkSideEffect(int flag)
|
|
97 {
|
|
98 return true;
|
|
99 }
|
|
100
|
|
101 version (DMDV2) {
|
|
102 bool canThrow()
|
|
103 {
|
|
104 /* assert()s are non-recoverable errors, so functions that
|
|
105 * use them can be considered "nothrow"
|
|
106 */
|
|
107 return 0; //(global.params.useAssert != 0);
|
|
108 }
|
|
109 }
|
|
110 void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
|
111 {
|
|
112 assert(false);
|
|
113 }
|
|
114
|
|
115 int inlineCost(InlineCostState* ics)
|
|
116 {
|
|
117 return 1 + e1.inlineCost(ics) + (msg ? msg.inlineCost(ics) : 0);
|
|
118 }
|
|
119
|
|
120 Expression doInline(InlineDoState ids)
|
|
121 {
|
|
122 AssertExp ae = cast(AssertExp)copy();
|
|
123
|
|
124 ae.e1 = e1.doInline(ids);
|
|
125 if (msg)
|
|
126 ae.msg = msg.doInline(ids);
|
|
127 return ae;
|
|
128 }
|
|
129
|
|
130 Expression inlineScan(InlineScanState* iss)
|
|
131 {
|
|
132 e1 = e1.inlineScan(iss);
|
|
133 if (msg)
|
|
134 msg = msg.inlineScan(iss);
|
|
135 return this;
|
|
136 }
|
|
137
|
|
138 static private void* castToVoid(int i)
|
|
139 {
|
|
140 return cast(void*)i;
|
|
141 }
|
|
142
|
|
143 elem* toElem(IRState* irs)
|
|
144 {
|
|
145 elem* e;
|
|
146 elem* ea;
|
|
147 Type t1 = e1.type.toBasetype();
|
|
148
|
|
149 //printf("AssertExp.toElem() %s\n", toChars());
|
|
150 if (global.params.useAssert)
|
|
151 {
|
|
152 e = e1.toElem(irs);
|
|
153
|
|
154 InvariantDeclaration inv = cast(InvariantDeclaration)castToVoid(1);
|
|
155
|
|
156 // If e1 is a class object, call the class invariant on it
|
|
157 if (global.params.useInvariants && t1.ty == Tclass &&
|
|
158 !(cast(TypeClass)t1).sym.isInterfaceDeclaration())
|
|
159 {
|
|
160 version (XXX) {///TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS
|
|
161 e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM__DINVARIANT]), e);
|
|
162 } else {
|
|
163 e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DINVARIANT]), e);
|
|
164 }
|
|
165 }
|
|
166 // If e1 is a struct object, call the struct invariant on it
|
|
167 else if (global.params.useInvariants &&
|
|
168 t1.ty == Tpointer &&
|
|
169 t1.nextOf().ty == Tstruct &&
|
|
170 (inv = (cast(TypeStruct)t1.nextOf()).sym.inv) !is null)
|
|
171 {
|
|
172 e = callfunc(loc, irs, 1, inv.type.nextOf(), e, e1.type, inv, inv.type, null, null);
|
|
173 }
|
|
174 else
|
|
175 {
|
|
176 // Construct: (e1 || ModuleAssert(line))
|
|
177 Symbol* sassert;
|
|
178 Module m = irs.blx.module_;
|
|
179 string mname = m.srcfile.toChars();
|
|
180
|
|
181 //printf("filename = '%s'\n", loc.filename);
|
|
182 //printf("module = '%s'\n", m.srcfile.toChars());
|
|
183
|
|
184 /* If the source file name has changed, probably due
|
|
185 * to a #line directive.
|
|
186 */
|
|
187 if (loc.filename && (msg || loc.filename != mname))
|
|
188 {
|
|
189 elem* efilename;
|
|
190
|
|
191 /* Cache values.
|
|
192 */
|
|
193 //static Symbol *assertexp_sfilename = null;
|
|
194 //static char *assertexp_name = null;
|
|
195 //static Module *assertexp_mn = null;
|
|
196
|
|
197 if (!assertexp_sfilename || loc.filename != assertexp_name || assertexp_mn != m)
|
|
198 {
|
|
199 dt_t* dt = null;
|
|
200
|
|
201 string id = loc.filename;
|
|
202 int len = id.length;
|
|
203 dtdword(&dt, len);
|
|
204 dtabytes(&dt,TYnptr, 0, len + 1, toStringz(id));
|
|
205
|
|
206 assertexp_sfilename = symbol_generate(SCstatic,type_fake(TYdarray));
|
|
207 assertexp_sfilename.Sdt = dt;
|
|
208 assertexp_sfilename.Sfl = FLdata;
|
|
209 version (ELFOBJ) {
|
|
210 assertexp_sfilename.Sseg = CDATA;
|
|
211 }
|
|
212 version (MACHOBJ) {
|
|
213 assertexp_sfilename.Sseg = DATA;
|
|
214 }
|
|
215 outdata(assertexp_sfilename);
|
|
216
|
|
217 assertexp_mn = m;
|
|
218 assertexp_name = id;
|
|
219 }
|
|
220
|
|
221 efilename = el_var(assertexp_sfilename);
|
|
222
|
|
223 if (msg)
|
|
224 {
|
|
225 elem* emsg = msg.toElem(irs);
|
|
226 ea = el_var(rtlsym[RTLSYM_DASSERT_MSG]);
|
|
227 ea = el_bin(OPcall, TYvoid, ea, el_params(el_long(TYint, loc.linnum), efilename, emsg, null));
|
|
228 }
|
|
229 else
|
|
230 {
|
|
231 ea = el_var(rtlsym[RTLSYM_DASSERT]);
|
|
232 ea = el_bin(OPcall, TYvoid, ea, el_param(el_long(TYint, loc.linnum), efilename));
|
|
233 }
|
|
234 }
|
|
235 else
|
|
236 {
|
|
237 sassert = m.toModuleAssert();
|
|
238 ea = el_bin(OPcall,TYvoid,el_var(sassert),
|
|
239 el_long(TYint, loc.linnum));
|
|
240 }
|
|
241 e = el_bin(OPoror,TYvoid,e,ea);
|
|
242 }
|
|
243 }
|
|
244 else
|
|
245 {
|
|
246 // BUG: should replace assert(0); with a HLT instruction
|
|
247 e = el_long(TYint, 0);
|
|
248 }
|
|
249 el_setLoc(e,loc);
|
|
250
|
|
251 return e;
|
|
252 }
|
|
253 }
|
|
254
|