Internally these would treat the cast same as a normal conversion from int[7] to int[], which allows code at CTFE to erroneously succeed where it would raise a SEGV at run-time.
1 |
/**
|
|
2 |
* Does the semantic 1 pass on the AST, which looks at symbol declarations but not initializers
|
|
3 |
* or function bodies.
|
|
4 |
*
|
|
5 |
* Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
|
|
6 |
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
|
7 |
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
|
8 |
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d, _dsymbolsem.d)
|
|
9 |
* Documentation: https://dlang.org/phobos/dmd_dsymbolsem.html
|
|
10 |
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbolsem.d
|
|
11 |
*/
|
|
12 |
|
|
13 |
module dmd.dsymbolsem; |
|
14 |
|
|
15 |
import core.stdc.stdio; |
|
16 |
import core.stdc.string; |
|
17 |
|
|
18 |
import dmd.aggregate; |
|
19 |
import dmd.aliasthis; |
|
20 |
import dmd.arraytypes; |
|
21 |
import dmd.astcodegen; |
|
22 |
import dmd.attrib; |
|
23 |
import dmd.blockexit; |
|
24 |
import dmd.clone; |
|
25 |
import dmd.compiler; |
|
26 |
import dmd.dcast; |
|
27 |
import dmd.dclass; |
|
28 |
import dmd.declaration; |
|
29 |
import dmd.denum; |
|
30 |
import dmd.dimport; |
|
31 |
import dmd.dinterpret; |
|
32 |
import dmd.dmangle; |
|
33 |
import dmd.dmodule; |
|
34 |
import dmd.dscope; |
|
35 |
import dmd.dstruct; |
|
36 |
import dmd.dsymbol; |
|
37 |
import dmd.dtemplate; |
|
38 |
import dmd.dversion; |
|
39 |
import dmd.errors; |
|
40 |
import dmd.escape; |
|
41 |
import dmd.expression; |
|
42 |
import dmd.expressionsem; |
|
43 |
import dmd.func; |
|
44 |
import dmd.globals; |
|
45 |
import dmd.id; |
|
46 |
import dmd.identifier; |
|
47 |
import dmd.init; |
|
48 |
import dmd.initsem; |
|
49 |
import dmd.hdrgen; |
|
50 |
import dmd.mtype; |
|
51 |
import dmd.nogc; |
|
52 |
import dmd.nspace; |
|
53 |
import dmd.objc; |
|
54 |
import dmd.opover; |
|
55 |
import dmd.parse; |
|
56 |
import dmd.root.filename; |
|
57 |
import dmd.root.outbuffer; |
|
58 |
import dmd.root.rmem; |
|
59 |
import dmd.root.rootobject; |
|
60 |
import dmd.semantic2; |
|
61 |
import dmd.semantic3; |
|
62 |
import dmd.sideeffect; |
|
63 |
import dmd.statementsem; |
|
64 |
import dmd.staticassert; |
|
65 |
import dmd.tokens; |
|
66 |
import dmd.utf; |
|
67 |
import dmd.utils; |
|
68 |
import dmd.statement; |
|
69 |
import dmd.target; |
|
70 |
import dmd.templateparamsem; |
|
71 |
import dmd.typesem; |
|
72 |
import dmd.visitor; |
|
73 |
|
|
74 |
enum LOG = false; |
|
75 |
|
|
76 |
/*****************************************
|
|
77 |
* Create inclusive postblit for struct by aggregating
|
|
78 |
* all the postblits in postblits[] with the postblits for
|
|
79 |
* all the members.
|
|
80 |
* Note the close similarity with AggregateDeclaration::buildDtor(),
|
|
81 |
* and the ordering changes (runs forward instead of backwards).
|
|
82 |
*/
|
|
83 |
private FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) |
|
84 |
{
|
|
85 |
//printf("StructDeclaration::buildPostBlit() %s\n", sd.toChars());
|
|
86 | 1 |
if (sd.isUnionDeclaration()) |
87 | 1 |
return null; |
88 |
|
|
89 |
// by default, the storage class of the created postblit
|
|
90 | 1 |
StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; |
91 | 1 |
Loc declLoc = sd.postblits.dim ? sd.postblits[0].loc : sd.loc; |
92 | 1 |
Loc loc; // internal code should have no loc to prevent coverage |
93 |
|
|
94 |
// if any of the postblits are disabled, then the generated postblit
|
|
95 |
// will be disabled
|
|
96 | 1 |
for (size_t i = 0; i < sd.postblits.dim; i++) |
97 |
{
|
|
98 | 1 |
stc |= sd.postblits[i].storage_class & STC.disable; |
99 |
}
|
|
100 |
|
|
101 | 1 |
VarDeclaration[] fieldsToDestroy; |
102 | 1 |
auto postblitCalls = new Statements(); |
103 |
// iterate through all the struct fields that are not disabled
|
|
104 | 1 |
for (size_t i = 0; i < sd.fields.dim && !(stc & STC.disable); i++) |
105 |
{
|
|
106 | 1 |
auto structField = sd.fields[i]; |
107 | 1 |
if (structField.storage_class & STC.ref_) |
108 |
continue; |
|
109 | 1 |
if (structField.overlapped) |
110 | 1 |
continue; |
111 |
// if it's a struct declaration or an array of structs
|
|
112 | 1 |
Type tv = structField.type.baseElemOf(); |
113 | 1 |
if (tv.ty != Tstruct) |
114 | 1 |
continue; |
115 | 1 |
auto sdv = (cast(TypeStruct)tv).sym; |
116 |
// which has a postblit declaration
|
|
117 | 1 |
if (!sdv.postblit) |
118 | 1 |
continue; |
119 | 1 |
assert(!sdv.isUnionDeclaration()); |
120 |
|
|
121 |
// if this field's postblit is not `nothrow`, add a `scope(failure)`
|
|
122 |
// block to destroy any prior successfully postblitted fields should
|
|
123 |
// this field's postblit fail
|
|
124 | 1 |
if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow) |
125 |
{
|
|
126 |
// create a list of destructors that need to be called
|
|
127 | 1 |
Expression[] dtorCalls; |
128 | 1 |
foreach(sf; fieldsToDestroy) |
129 |
{
|
|
130 | 1 |
Expression ex; |
131 | 1 |
tv = sf.type.toBasetype(); |
132 | 1 |
if (tv.ty == Tstruct) |
133 |
{
|
|
134 |
// this.v.__xdtor()
|
|
135 |
|
|
136 | 1 |
ex = new ThisExp(loc); |
137 | 1 |
ex = new DotVarExp(loc, ex, sf); |
138 |
|
|
139 |
// This is a hack so we can call destructors on const/immutable objects.
|
|
140 | 1 |
ex = new AddrExp(loc, ex); |
141 | 1 |
ex = new CastExp(loc, ex, sf.type.mutableOf().pointerTo()); |
142 | 1 |
ex = new PtrExp(loc, ex); |
143 | 1 |
if (stc & STC.safe) |
144 |
stc = (stc & ~STC.safe) | STC.trusted; |
|
145 |
|
|
146 | 1 |
auto sfv = (cast(TypeStruct)sf.type.baseElemOf()).sym; |
147 |
|
|
148 | 1 |
ex = new DotVarExp(loc, ex, sfv.dtor, false); |
149 | 1 |
ex = new CallExp(loc, ex); |
150 |
|
|
151 | 1 |
dtorCalls ~= ex; |
152 |
}
|
|
153 |
else
|
|
154 |
{
|
|
155 |
// _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
|
|
156 |
|
|
157 | 1 |
const length = tv.numberOfElems(loc); |
158 |
|
|
159 | 1 |
ex = new ThisExp(loc); |
160 | 1 |
ex = new DotVarExp(loc, ex, sf); |
161 |
|
|
162 |
// This is a hack so we can call destructors on const/immutable objects.
|
|
163 | 1 |
ex = new DotIdExp(loc, ex, Id.ptr); |
164 | 1 |
ex = new CastExp(loc, ex, sdv.type.pointerTo()); |
165 | 1 |
if (stc & STC.safe) |
166 |
stc = (stc & ~STC.safe) | STC.trusted; |
|
167 |
|
|
168 | 1 |
auto se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), |
169 |
new IntegerExp(loc, length, Type.tsize_t)); |
|
170 |
// Prevent redundant bounds check
|
|
171 | 1 |
se.upperIsInBounds = true; |
172 | 1 |
se.lowerIsLessThanUpper = true; |
173 |
|
|
174 | 1 |
ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se); |
175 |
|
|
176 | 1 |
dtorCalls ~= ex; |
177 |
}
|
|
178 |
}
|
|
179 | 1 |
fieldsToDestroy = []; |
180 |
|
|
181 |
// aggregate the destructor calls
|
|
182 | 1 |
auto dtors = new Statements(); |
183 | 1 |
foreach_reverse(dc; dtorCalls) |
184 |
{
|
|
185 | 1 |
dtors.push(new ExpStatement(loc, dc)); |
186 |
}
|
|
187 |
|
|
188 |
// put destructor calls in a `scope(failure)` block
|
|
189 | 1 |
postblitCalls.push(new ScopeGuardStatement(loc, TOK.onScopeFailure, new CompoundStatement(loc, dtors))); |
190 |
}
|
|
191 |
|
|
192 |
// perform semantic on the member postblit in order to
|
|
193 |
// be able to aggregate it later on with the rest of the
|
|
194 |
// postblits
|
|
195 | 1 |
sdv.postblit.functionSemantic(); |
196 |
|
|
197 | 1 |
stc = mergeFuncAttrs(stc, sdv.postblit); |
198 | 1 |
stc = mergeFuncAttrs(stc, sdv.dtor); |
199 |
|
|
200 |
// if any of the struct member fields has disabled
|
|
201 |
// its postblit, then `sd` is not copyable, so no
|
|
202 |
// postblit is generated
|
|
203 | 1 |
if (stc & STC.disable) |
204 |
{
|
|
205 | 1 |
postblitCalls.setDim(0); |
206 | 1 |
break; |
207 |
}
|
|
208 |
|
|
209 | 1 |
Expression ex; |
210 | 1 |
tv = structField.type.toBasetype(); |
211 | 1 |
if (tv.ty == Tstruct) |
212 |
{
|
|
213 |
// this.v.__xpostblit()
|
|
214 |
|
|
215 | 1 |
ex = new ThisExp(loc); |
216 | 1 |
ex = new DotVarExp(loc, ex, structField); |
217 |
|
|
218 |
// This is a hack so we can call postblits on const/immutable objects.
|
|
219 | 1 |
ex = new AddrExp(loc, ex); |
220 | 1 |
ex = new CastExp(loc, ex, structField.type.mutableOf().pointerTo()); |
221 | 1 |
ex = new PtrExp(loc, ex); |
222 | 1 |
if (stc & STC.safe) |
223 | 1 |
stc = (stc & ~STC.safe) | STC.trusted; |
224 |
|
|
225 | 1 |
ex = new DotVarExp(loc, ex, sdv.postblit, false); |
226 | 1 |
ex = new CallExp(loc, ex); |
227 |
}
|
|
228 |
else
|
|
229 |
{
|
|
230 |
// _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
|
|
231 |
|
|
232 | 1 |
const length = tv.numberOfElems(loc); |
233 | 1 |
if (length == 0) |
234 | 1 |
continue; |
235 |
|
|
236 | 1 |
ex = new ThisExp(loc); |
237 | 1 |
ex = new DotVarExp(loc, ex, structField); |
238 |
|
|
239 |
// This is a hack so we can call postblits on const/immutable objects.
|
|
240 | 1 |
ex = new DotIdExp(loc, ex, Id.ptr); |
241 | 1 |
ex = new CastExp(loc, ex, sdv.type.pointerTo()); |
242 | 1 |
if (stc & STC.safe) |
243 |
stc = (stc & ~STC.safe) | STC.trusted; |
|
244 |
|
|
245 | 1 |
auto se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), |
246 |
new IntegerExp(loc, length, Type.tsize_t)); |
|
247 |
// Prevent redundant bounds check
|
|
248 | 1 |
se.upperIsInBounds = true; |
249 | 1 |
se.lowerIsLessThanUpper = true; |
250 | 1 |
ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayPostblit), se); |
251 |
}
|
|
252 | 1 |
postblitCalls.push(new ExpStatement(loc, ex)); // combine in forward order |
253 |
|
|
254 |
/* https://issues.dlang.org/show_bug.cgi?id=10972
|
|
255 |
* When subsequent field postblit calls fail,
|
|
256 |
* this field should be destructed for Exception Safety.
|
|
257 |
*/
|
|
258 | 1 |
if (sdv.dtor) |
259 |
{
|
|
260 | 1 |
sdv.dtor.functionSemantic(); |
261 |
|
|
262 |
// keep a list of fields that need to be destroyed in case
|
|
263 |
// of a future postblit failure
|
|
264 | 1 |
fieldsToDestroy ~= structField; |
265 |
}
|
|
266 |
}
|
|
267 |
|
|
268 |
void checkShared() |
|
269 |
{
|
|
270 | 1 |
if (sd.type.isShared()) |
271 |
stc |= STC.shared_; |
|
272 |
}
|
|
273 |
|
|
274 |
// Build our own "postblit" which executes a, but only if needed.
|
|
275 | 1 |
if (postblitCalls.dim || (stc & STC.disable)) |
276 |
{
|
|
277 |
//printf("Building __fieldPostBlit()\n");
|
|
278 | 1 |
checkShared(); |
279 | 1 |
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit); |
280 | 1 |
dd.generated = true; |
281 | 1 |
dd.storage_class |= STC.inference; |
282 | 1 |
dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls); |
283 | 1 |
sd.postblits.shift(dd); |
284 | 1 |
sd.members.push(dd); |
285 | 1 |
dd.dsymbolSemantic(sc); |
286 |
}
|
|
287 |
|
|
288 |
// create __xpostblit, which is the generated postblit
|
|
289 | 1 |
FuncDeclaration xpostblit = null; |
290 | 1 |
switch (sd.postblits.dim) |
291 |
{
|
|
292 | 1 |
case 0: |
293 | 1 |
break; |
294 |
|
|
295 | 1 |
case 1: |
296 | 1 |
xpostblit = sd.postblits[0]; |
297 | 1 |
break; |
298 |
|
|
299 | 1 |
default: |
300 | 1 |
Expression e = null; |
301 | 1 |
stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; |
302 | 1 |
for (size_t i = 0; i < sd.postblits.dim; i++) |
303 |
{
|
|
304 | 1 |
auto fd = sd.postblits[i]; |
305 | 1 |
stc = mergeFuncAttrs(stc, fd); |
306 | 1 |
if (stc & STC.disable) |
307 |
{
|
|
308 | 1 |
e = null; |
309 | 1 |
break; |
310 |
}
|
|
311 | 1 |
Expression ex = new ThisExp(loc); |
312 | 1 |
ex = new DotVarExp(loc, ex, fd, false); |
313 | 1 |
ex = new CallExp(loc, ex); |
314 | 1 |
e = Expression.combine(e, ex); |
315 |
}
|
|
316 |
|
|
317 | 1 |
checkShared(); |
318 | 1 |
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit); |
319 | 1 |
dd.generated = true; |
320 | 1 |
dd.storage_class |= STC.inference; |
321 | 1 |
dd.fbody = new ExpStatement(loc, e); |
322 | 1 |
sd.members.push(dd); |
323 | 1 |
dd.dsymbolSemantic(sc); |
324 | 1 |
xpostblit = dd; |
325 | 1 |
break; |
326 |
}
|
|
327 |
|
|
328 |
// Add an __xpostblit alias to make the inclusive postblit accessible
|
|
329 | 1 |
if (xpostblit) |
330 |
{
|
|
331 | 1 |
auto _alias = new AliasDeclaration(Loc.initial, Id.__xpostblit, xpostblit); |
332 | 1 |
_alias.dsymbolSemantic(sc); |
333 | 1 |
sd.members.push(_alias); |
334 | 1 |
_alias.addMember(sc, sd); // add to symbol table |
335 |
}
|
|
336 | 1 |
return xpostblit; |
337 |
}
|
|
338 |
|
|
339 |
/**
|
|
340 |
* Generates a copy constructor declaration with the specified storage
|
|
341 |
* class for the parameter and the function.
|
|
342 |
*
|
|
343 |
* Params:
|
|
344 |
* sd = the `struct` that contains the copy constructor
|
|
345 |
* paramStc = the storage class of the copy constructor parameter
|
|
346 |
* funcStc = the storage class for the copy constructor declaration
|
|
347 |
*
|
|
348 |
* Returns:
|
|
349 |
* The copy constructor declaration for struct `sd`.
|
|
350 |
*/
|
|
351 |
private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc) |
|
352 |
{
|
|
353 | 1 |
auto fparams = new Parameters(); |
354 | 1 |
auto structType = sd.type; |
355 | 1 |
fparams.push(new Parameter(paramStc | STC.ref_ | STC.return_ | STC.scope_, structType, Id.p, null, null)); |
356 | 1 |
ParameterList pList = ParameterList(fparams); |
357 | 1 |
auto tf = new TypeFunction(pList, structType, LINK.d, STC.ref_); |
358 | 1 |
auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true); |
359 | 1 |
ccd.storage_class |= funcStc; |
360 | 1 |
ccd.storage_class |= STC.inference; |
361 | 1 |
ccd.generated = true; |
362 | 1 |
return ccd; |
363 |
}
|
|
364 |
|
|
365 |
/**
|
|
366 |
* Generates a trivial copy constructor body that simply does memberwise
|
|
367 |
* initialization:
|
|
368 |
*
|
|
369 |
* this.field1 = rhs.field1;
|
|
370 |
* this.field2 = rhs.field2;
|
|
371 |
* ...
|
|
372 |
*
|
|
373 |
* Params:
|
|
374 |
* sd = the `struct` declaration that contains the copy constructor
|
|
375 |
*
|
|
376 |
* Returns:
|
|
377 |
* A `CompoundStatement` containing the body of the copy constructor.
|
|
378 |
*/
|
|
379 |
private Statement generateCopyCtorBody(StructDeclaration sd) |
|
380 |
{
|
|
381 | 1 |
Loc loc; |
382 | 1 |
Expression e; |
383 | 1 |
foreach (v; sd.fields) |
384 |
{
|
|
385 | 1 |
auto ec = new AssignExp(loc, |
386 |
new DotVarExp(loc, new ThisExp(loc), v), |
|
387 |
new DotVarExp(loc, new IdentifierExp(loc, Id.p), v)); |
|
388 | 1 |
e = Expression.combine(e, ec); |
389 |
//printf("e.toChars = %s\n", e.toChars());
|
|
390 |
}
|
|
391 | 1 |
Statement s1 = new ExpStatement(loc, e); |
392 | 1 |
return new CompoundStatement(loc, s1); |
393 |
}
|
|
394 |
|
|
395 |
/**
|
|
396 |
* Generates a copy constructor for a specified `struct` sd if
|
|
397 |
* the following conditions are met:
|
|
398 |
*
|
|
399 |
* 1. sd does not define a copy constructor
|
|
400 |
* 2. at least one field of sd defines a copy constructor
|
|
401 |
*
|
|
402 |
* If the above conditions are met, the following copy constructor
|
|
403 |
* is generated:
|
|
404 |
*
|
|
405 |
* this(ref return scope inout(S) rhs) inout
|
|
406 |
* {
|
|
407 |
* this.field1 = rhs.field1;
|
|
408 |
* this.field2 = rhs.field2;
|
|
409 |
* ...
|
|
410 |
* }
|
|
411 |
*
|
|
412 |
* Params:
|
|
413 |
* sd = the `struct` for which the copy constructor is generated
|
|
414 |
* sc = the scope where the copy constructor is generated
|
|
415 |
*
|
|
416 |
* Returns:
|
|
417 |
* `true` if `struct` sd defines a copy constructor (explicitly or generated),
|
|
418 |
* `false` otherwise.
|
|
419 |
*/
|
|
420 |
private bool buildCopyCtor(StructDeclaration sd, Scope* sc) |
|
421 |
{
|
|
422 | 1 |
if (global.errors) |
423 | 1 |
return false; |
424 |
|
|
425 | 1 |
bool hasPostblit; |
426 | 1 |
if (sd.postblit && !sd.postblit.isDisabled()) |
427 | 1 |
hasPostblit = true; |
428 |
|
|
429 | 1 |
auto ctor = sd.search(sd.loc, Id.ctor); |
430 | 1 |
CtorDeclaration cpCtor; |
431 | 1 |
CtorDeclaration rvalueCtor; |
432 | 1 |
if (ctor) |
433 |
{
|
|
434 | 1 |
if (ctor.isOverloadSet()) |
435 | 1 |
return false; |
436 | 1 |
if (auto td = ctor.isTemplateDeclaration()) |
437 | 1 |
ctor = td.funcroot; |
438 |
}
|
|
439 |
|
|
440 | 1 |
if (!ctor) |
441 | 1 |
goto LcheckFields; |
442 |
|
|
443 | 1 |
overloadApply(ctor, (Dsymbol s) |
444 |
{
|
|
445 | 1 |
if (s.isTemplateDeclaration()) |
446 | 1 |
return 0; |
447 | 1 |
auto ctorDecl = s.isCtorDeclaration(); |
448 | 1 |
assert(ctorDecl); |
449 | 1 |
if (ctorDecl.isCpCtor) |
450 |
{
|
|
451 | 1 |
if (!cpCtor) |
452 | 1 |
cpCtor = ctorDecl; |
453 | 1 |
return 0; |
454 |
}
|
|
455 |
|
|
456 | 1 |
auto tf = ctorDecl.type.toTypeFunction(); |
457 | 1 |
const dim = tf.parameterList.length; |
458 | 1 |
if (dim == 1) |
459 |
{
|
|
460 | 1 |
auto param = tf.parameterList[0]; |
461 | 1 |
if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) |
462 |
{
|
|
463 | 1 |
rvalueCtor = ctorDecl; |
464 |
}
|
|
465 |
}
|
|
466 | 1 |
return 0; |
467 |
});
|
|
468 |
|
|
469 | 1 |
if (cpCtor && rvalueCtor) |
470 |
{
|
|
471 | 1 |
.error(sd.loc, "`struct %s` may not define both a rvalue constructor and a copy constructor", sd.toChars()); |
472 | 1 |
errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here"); |
473 | 1 |
errorSupplemental(cpCtor.loc, "copy constructor defined here"); |
474 | 1 |
return true; |
475 |
}
|
|
476 | 1 |
else if (cpCtor) |
477 |
{
|
|
478 | 1 |
return !hasPostblit; |
479 |
}
|
|
480 |
|
|
481 |
LcheckFields: |
|
482 | 1 |
VarDeclaration fieldWithCpCtor; |
483 |
// see if any struct members define a copy constructor
|
|
484 | 1 |
foreach (v; sd.fields) |
485 |
{
|
|
486 | 1 |
if (v.storage_class & STC.ref_) |
487 |
continue; |
|
488 | 1 |
if (v.overlapped) |
489 | 1 |
continue; |
490 |
|
|
491 | 1 |
auto ts = v.type.baseElemOf().isTypeStruct(); |
492 | 1 |
if (!ts) |
493 | 1 |
continue; |
494 | 1 |
if (ts.sym.hasCopyCtor) |
495 |
{
|
|
496 | 1 |
fieldWithCpCtor = v; |
497 | 1 |
break; |
498 |
}
|
|
499 |
}
|
|
500 |
|
|
501 | 1 |
if (fieldWithCpCtor && rvalueCtor) |
502 |
{
|
|
503 | 1 |
.error(sd.loc, "`struct %s` may not define a rvalue constructor and have fields with copy constructors", sd.toChars()); |
504 | 1 |
errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here"); |
505 | 1 |
errorSupplemental(fieldWithCpCtor.loc, "field with copy constructor defined here"); |
506 | 1 |
return false; |
507 |
}
|
|
508 | 1 |
else if (!fieldWithCpCtor) |
509 | 1 |
return false; |
510 |
|
|
511 | 1 |
if (hasPostblit) |
512 |
return false; |
|
513 |
|
|
514 |
//printf("generating copy constructor for %s\n", sd.toChars());
|
|
515 | 1 |
const MOD paramMod = MODFlags.wild; |
516 | 1 |
const MOD funcMod = MODFlags.wild; |
517 | 1 |
auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod)); |
518 | 1 |
auto copyCtorBody = generateCopyCtorBody(sd); |
519 | 1 |
ccd.fbody = copyCtorBody; |
520 | 1 |
sd.members.push(ccd); |
521 | 1 |
ccd.addMember(sc, sd); |
522 | 1 |
const errors = global.startGagging(); |
523 | 1 |
Scope* sc2 = sc.push(); |
524 | 1 |
sc2.stc = 0; |
525 | 1 |
sc2.linkage = LINK.d; |
526 | 1 |
ccd.dsymbolSemantic(sc2); |
527 | 1 |
ccd.semantic2(sc2); |
528 | 1 |
ccd.semantic3(sc2); |
529 |
//printf("ccd semantic: %s\n", ccd.type.toChars());
|
|
530 | 1 |
sc2.pop(); |
531 | 1 |
if (global.endGagging(errors)) |
532 |
{
|
|
533 | 1 |
ccd.storage_class |= STC.disable; |
534 | 1 |
ccd.fbody = null; |
535 |
}
|
|
536 | 1 |
return true; |
537 |
}
|
|
538 |
|
|
539 |
private uint setMangleOverride(Dsymbol s, const(char)[] sym) |
|
540 |
{
|
|
541 | 1 |
if (s.isFuncDeclaration() || s.isVarDeclaration()) |
542 |
{
|
|
543 | 1 |
s.isDeclaration().mangleOverride = sym; |
544 | 1 |
return 1; |
545 |
}
|
|
546 |
|
|
547 | 1 |
if (auto ad = s.isAttribDeclaration()) |
548 |
{
|
|
549 | 1 |
uint nestedCount = 0; |
550 |
|
|
551 | 1 |
ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } ); |
552 |
|
|
553 | 1 |
return nestedCount; |
554 |
}
|
|
555 |
return 0; |
|
556 |
}
|
|
557 |
|
|
558 |
/*************************************
|
|
559 |
* Does semantic analysis on the public face of declarations.
|
|
560 |
*/
|
|
561 |
extern(C++) void dsymbolSemantic(Dsymbol dsym, Scope* sc) |
|
562 |
{
|
|
563 | 1 |
scope v = new DsymbolSemanticVisitor(sc); |
564 | 1 |
dsym.accept(v); |
565 |
}
|
|
566 |
|
|
567 |
structalign_t getAlignment(AlignDeclaration ad, Scope* sc) |
|
568 |
{
|
|
569 | 1 |
if (ad.salign != ad.UNKNOWN) |
570 | 1 |
return ad.salign; |
571 |
|
|
572 | 1 |
if (!ad.ealign) |
573 | 1 |
return ad.salign = STRUCTALIGN_DEFAULT; |
574 |
|
|
575 | 1 |
sc = sc.startCTFE(); |
576 | 1 |
ad.ealign = ad.ealign.expressionSemantic(sc); |
577 | 1 |
ad.ealign = resolveProperties(sc, ad.ealign); |
578 | 1 |
sc = sc.endCTFE(); |
579 | 1 |
ad.ealign = ad.ealign.ctfeInterpret(); |
580 |
|
|
581 | 1 |
if (ad.ealign.op == TOK.error) |
582 | 1 |
return ad.salign = STRUCTALIGN_DEFAULT; |
583 |
|
|
584 | 1 |
Type tb = ad.ealign.type.toBasetype(); |
585 | 1 |
auto n = ad.ealign.toInteger(); |
586 |
|
|
587 | 1 |
if (n < 1 || n & (n - 1) || structalign_t.max < n || !tb.isintegral()) |
588 |
{
|
|
589 | 1 |
error(ad.loc, "alignment must be an integer positive power of 2, not %s", ad.ealign.toChars()); |
590 | 1 |
return ad.salign = STRUCTALIGN_DEFAULT; |
591 |
}
|
|
592 |
|
|
593 | 1 |
return ad.salign = cast(structalign_t)n; |
594 |
}
|
|
595 |
|
|
596 |
const(char)* getMessage(DeprecatedDeclaration dd) |
|
597 |
{
|
|
598 | 1 |
if (auto sc = dd._scope) |
599 |
{
|
|
600 | 1 |
dd._scope = null; |
601 |
|
|
602 | 1 |
sc = sc.startCTFE(); |
603 | 1 |
dd.msg = dd.msg.expressionSemantic(sc); |
604 | 1 |
dd.msg = resolveProperties(sc, dd.msg); |
605 | 1 |
sc = sc.endCTFE(); |
606 | 1 |
dd.msg = dd.msg.ctfeInterpret(); |
607 |
|
|
608 | 1 |
if (auto se = dd.msg.toStringExp()) |
609 | 1 |
dd.msgstr = se.toStringz().ptr; |
610 |
else
|
|
611 |
dd.msg.error("compile time constant expected, not `%s`", dd.msg.toChars()); |
|
612 |
}
|
|
613 | 1 |
return dd.msgstr; |
614 |
}
|
|
615 |
|
|
616 |
|
|
617 |
// Returns true if a contract can appear without a function body.
|
|
618 |
package bool allowsContractWithoutBody(FuncDeclaration funcdecl) |
|
619 |
{
|
|
620 | 1 |
assert(!funcdecl.fbody); |
621 |
|
|
622 |
/* Contracts can only appear without a body when they are virtual
|
|
623 |
* interface functions or abstract.
|
|
624 |
*/
|
|
625 | 1 |
Dsymbol parent = funcdecl.toParent(); |
626 | 1 |
InterfaceDeclaration id = parent.isInterfaceDeclaration(); |
627 |
|
|
628 | 1 |
if (!funcdecl.isAbstract() && |
629 | 1 |
(funcdecl.fensures || funcdecl.frequires) && |
630 | 1 |
!(id && funcdecl.isVirtual())) |
631 |
{
|
|
632 | 1 |
auto cd = parent.isClassDeclaration(); |
633 | 1 |
if (!(cd && cd.isAbstract())) |
634 | 1 |
return false; |
635 |
}
|
|
636 | 1 |
return true; |
637 |
}
|
|
638 |
|
|
639 |
private extern(C++) final class DsymbolSemanticVisitor : Visitor |
|
640 |
{
|
|
641 |
alias visit = Visitor.visit; |
|
642 |
|
|
643 |
Scope* sc; |
|
644 | 1 |
this(Scope* sc) |
645 |
{
|
|
646 | 1 |
this.sc = sc; |
647 |
}
|
|
648 |
|
|
649 |
// Save the scope and defer semantic analysis on the Dsymbol.
|
|
650 |
private void deferDsymbolSemantic(Dsymbol s, Scope *scx) |
|
651 |
{
|
|
652 | 1 |
s._scope = scx ? scx : sc.copy(); |
653 | 1 |
s._scope.setNoFree(); |
654 | 1 |
Module.addDeferredSemantic(s); |
655 |
}
|
|
656 |
|
|
657 |
override void visit(Dsymbol dsym) |
|
658 |
{
|
|
659 |
dsym.error("%p has no semantic routine", dsym); |
|
660 |
}
|
|
661 |
|
|
662 |
override void visit(ScopeDsymbol) { } |
|
663 |
override void visit(Declaration) { } |
|
664 |
|
|
665 |
override void visit(AliasThis dsym) |
|
666 |
{
|
|
667 | 1 |
if (dsym.semanticRun != PASS.init) |
668 | 1 |
return; |
669 |
|
|
670 | 1 |
if (dsym._scope) |
671 |
{
|
|
672 | 1 |
sc = dsym._scope; |
673 | 1 |
dsym._scope = null; |
674 |
}
|
|
675 |
|
|
676 | 1 |
if (!sc) |
677 |
return; |
|
678 |
|
|
679 | 1 |
dsym.semanticRun = PASS.semantic; |
680 | 1 |
dsym.isDeprecated_ = !!(sc.stc & STC.deprecated_); |
681 |
|
|
682 | 1 |
Dsymbol p = sc.parent.pastMixin(); |
683 | 1 |
AggregateDeclaration ad = p.isAggregateDeclaration(); |
684 | 1 |
if (!ad) |
685 |
{
|
|
686 | 1 |
error(dsym.loc, "alias this can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); |
687 | 1 |
return; |
688 |
}
|
|
689 |
|
|
690 | 1 |
assert(ad.members); |
691 | 1 |
Dsymbol s = ad.search(dsym.loc, dsym.ident); |
692 | 1 |
if (!s) |
693 |
{
|
|
694 | 1 |
s = sc.search(dsym.loc, dsym.ident, null); |
695 | 1 |
if (s) |
696 |
error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); |
|
697 |
else
|
|
698 | 1 |
error(dsym.loc, "undefined identifier `%s`", dsym.ident.toChars()); |
699 | 1 |
return; |
700 |
}
|
|
701 | 1 |
if (ad.aliasthis && s != ad.aliasthis) |
702 |
{
|
|
703 |
error(dsym.loc, "there can be only one alias this"); |
|
704 |
return; |
|
705 |
}
|
|
706 |
|
|
707 |
/* disable the alias this conversion so the implicit conversion check
|
|
708 |
* doesn't use it.
|
|
709 |
*/
|
|
710 | 1 |
ad.aliasthis = null; |
711 |
|
|
712 | 1 |
Dsymbol sx = s; |
713 | 1 |
if (sx.isAliasDeclaration()) |
714 | 1 |
sx = sx.toAlias(); |
715 | 1 |
Declaration d = sx.isDeclaration(); |
716 | 1 |
if (d && !d.isTupleDeclaration()) |
717 |
{
|
|
718 |
/* https://issues.dlang.org/show_bug.cgi?id=18429
|
|
719 |
*
|
|
720 |
* If the identifier in the AliasThis declaration
|
|
721 |
* is defined later and is a voldemort type, we must
|
|
722 |
* perform semantic on the declaration to deduce the type.
|
|
723 |
*/
|
|
724 | 1 |
if (!d.type) |
725 | 1 |
d.dsymbolSemantic(sc); |
726 |
|
|
727 | 1 |
Type t = d.type; |
728 | 1 |
assert(t); |
729 | 1 |
if (ad.type.implicitConvTo(t) > MATCH.nomatch) |
730 |
{
|
|
731 | 1 |
error(dsym.loc, "alias this is not reachable as `%s` already converts to `%s`", ad.toChars(), t.toChars()); |
732 |
}
|
|
733 |
}
|
|
734 |
|
|
735 | 1 |
dsym.sym = s; |
736 |
// Restore alias this
|
|
737 | 1 |
ad.aliasthis = dsym; |
738 | 1 |
dsym.semanticRun = PASS.semanticdone; |
739 |
}
|
|
740 |
|
|
741 |
override void visit(AliasDeclaration dsym) |
|
742 |
{
|
|
743 | 1 |
if (dsym.semanticRun >= PASS.semanticdone) |
744 | 1 |
return; |
745 | 1 |
assert(dsym.semanticRun <= PASS.semantic); |
746 |
|
|
747 | 1 |
dsym.storage_class |= sc.stc & STC.deprecated_; |
748 | 1 |
dsym.protection = sc.protection; |
749 | 1 |
dsym.userAttribDecl = sc.userAttribDecl; |
750 |
|
|
751 | 1 |
if (!sc.func && dsym.inNonRoot()) |
752 | 1 |
return; |
753 |
|
|
754 | 1 |
aliasSemantic(dsym, sc); |
755 |
}
|
|
756 |
|
|
757 |
override void visit(VarDeclaration dsym) |
|
758 |
{
|
|
759 |
version (none) |
|
760 |
{
|
|
761 |
printf("VarDeclaration::semantic('%s', parent = '%s') sem = %d\n", |
|
762 |
dsym.toChars(), sc.parent ? sc.parent.toChars() : null, dsym.semanticRun); |
|
763 |
printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null"); |
|
764 |
printf(" stc = x%x\n", dsym.storage_class.stc); |
|
765 |
printf(" storage_class = x%llx\n", dsym.storage_class); |
|
766 |
printf("linkage = %d\n", dsym.linkage); |
|
767 |
//if (strcmp(toChars(), "mul") == 0) assert(0);
|
|
768 |
}
|
|
769 |
//if (semanticRun > PASS.init)
|
|
770 |
// return;
|
|
771 |
//semanticRun = PSSsemantic;
|
|
772 |
|
|
773 | 1 |
if (dsym.semanticRun >= PASS.semanticdone) |
774 | 1 |
return; |
775 |
|
|
776 | 1 |
if (sc && sc.inunion && sc.inunion.isAnonDeclaration()) |
777 | 1 |
dsym.overlapped = true; |
778 |
|
|
779 | 1 |
Scope* scx = null; |
780 | 1 |
if (dsym._scope) |
781 |
{
|
|
782 | 1 |
sc = dsym._scope; |
783 | 1 |
scx = sc; |
784 | 1 |
dsym._scope = null; |
785 |
}
|
|
786 |
|
|
787 | 1 |
if (!sc) |
788 | 1 |
return; |
789 |
|
|
790 | 1 |
dsym.semanticRun = PASS.semantic; |
791 |
|
|
792 |
/* Pick up storage classes from context, but except synchronized,
|
|
793 |
* override, abstract, and final.
|
|
794 |
*/
|
|
795 | 1 |
dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_)); |
796 | 1 |
if (dsym.storage_class & STC.extern_ && dsym._init) |
797 |
dsym.error("extern symbols cannot have initializers"); |
|
798 |
|
|
799 | 1 |
dsym.userAttribDecl = sc.userAttribDecl; |
800 | 1 |
dsym.cppnamespace = sc.namespace; |
801 |
|
|
802 | 1 |
AggregateDeclaration ad = dsym.isThis(); |
803 | 1 |
if (ad) |
804 | 1 |
dsym.storage_class |= ad.storage_class & STC.TYPECTOR; |
805 |
|
|
806 |
/* If auto type inference, do the inference
|
|
807 |
*/
|
|
808 | 1 |
int inferred = 0; |
809 | 1 |
if (!dsym.type) |
810 |
{
|
|
811 | 1 |
dsym.inuse++; |
812 |
|
|
813 |
// Infering the type requires running semantic,
|
|
814 |
// so mark the scope as ctfe if required
|
|
815 | 1 |
bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0; |
816 | 1 |
if (needctfe) |
817 |
{
|
|
818 | 1 |
sc.flags |= SCOPE.condition; |
819 | 1 |
sc = sc.startCTFE(); |
820 |
}
|
|
821 |
//printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars());
|
|
822 | 1 |
dsym._init = dsym._init.inferType(sc); |
823 | 1 |
dsym.type = dsym._init.initializerToExpression().type; |
824 | 1 |
if (needctfe) |
825 | 1 |
sc = sc.endCTFE(); |
826 |
|
|
827 | 1 |
dsym.inuse--; |
828 | 1 |
inferred = 1; |
829 |
|
|
830 |
/* This is a kludge to support the existing syntax for RAII
|
|
831 |
* declarations.
|
|
832 |
*/
|
|
833 | 1 |
dsym.storage_class &= ~STC.auto_; |
834 | 1 |
dsym.originalType = dsym.type.syntaxCopy(); |
835 |
}
|
|
836 |
else
|
|
837 |
{
|
|
838 | 1 |
if (!dsym.originalType) |
839 | 1 |
dsym.originalType = dsym.type.syntaxCopy(); |
840 |
|
|
841 |
/* Prefix function attributes of variable declaration can affect
|
|
842 |
* its type:
|
|
843 |
* pure nothrow void function() fp;
|
|
844 |
* static assert(is(typeof(fp) == void function() pure nothrow));
|
|
845 |
*/
|
|
846 | 1 |
Scope* sc2 = sc.push(); |
847 | 1 |
sc2.stc |= (dsym.storage_class & STC.FUNCATTR); |
848 | 1 |
dsym.inuse++; |
849 | 1 |
dsym.type = dsym.type.typeSemantic(dsym.loc, sc2); |
850 | 1 |
dsym.inuse--; |
851 | 1 |
sc2.pop(); |
852 |
}
|
|
853 |
//printf(" semantic type = %s\n", dsym.type ? dsym.type.toChars() : "null");
|
|
854 | 1 |
if (dsym.type.ty == Terror) |
855 | 1 |
dsym.errors = true; |
856 |
|
|
857 | 1 |
dsym.type.checkDeprecated(dsym.loc, sc); |
858 | 1 |
dsym.linkage = sc.linkage; |
859 | 1 |
dsym.parent = sc.parent; |
860 |
//printf("this = %p, parent = %p, '%s'\n", dsym, dsym.parent, dsym.parent.toChars());
|
|
861 | 1 |
dsym.protection = sc.protection; |
862 |
|
|
863 |
/* If scope's alignment is the default, use the type's alignment,
|
|
864 |
* otherwise the scope overrrides.
|
|
865 |
*/
|
|
866 | 1 |
dsym.alignment = sc.alignment(); |
867 | 1 |
if (dsym.alignment == STRUCTALIGN_DEFAULT) |
868 | 1 |
dsym.alignment = dsym.type.alignment(); // use type's alignment |
869 |
|
|
870 |
//printf("sc.stc = %x\n", sc.stc);
|
|
871 |
//printf("storage_class = x%x\n", storage_class);
|
|
872 |
|
|
873 | 1 |
if (global.params.vcomplex) |
874 | 1 |
dsym.type.checkComplexTransition(dsym.loc, sc); |
875 |
|
|
876 |
// Calculate type size + safety checks
|
|
877 | 1 |
if (sc.func && !sc.intypeof) |
878 |
{
|
|
879 | 1 |
if (dsym.storage_class & STC.gshared && !dsym.isMember()) |
880 |
{
|
|
881 | 1 |
if (sc.func.setUnsafe()) |
882 |
dsym.error("__gshared not allowed in safe functions; use shared"); |
|
883 |
}
|
|
884 |
}
|
|
885 |
|
|
886 | 1 |
Dsymbol parent = dsym.toParent(); |
887 |
|
|
888 | 1 |
Type tb = dsym.type.toBasetype(); |
889 | 1 |
Type tbn = tb.baseElemOf(); |
890 | 1 |
if (tb.ty == Tvoid && !(dsym.storage_class & STC.lazy_)) |
891 |
{
|
|
892 | 1 |
if (inferred) |
893 |
{
|
|
894 | 1 |
dsym.error("type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars()); |
895 |
}
|
|
896 |
else
|
|
897 | 1 |
dsym.error("variables cannot be of type `void`"); |
898 | 1 |
dsym.type = Type.terror; |
899 | 1 |
tb = dsym.type; |
900 |
}
|
|
901 | 1 |
if (tb.ty == Tfunction) |
902 |
{
|
|
903 | 1 |
dsym.error("cannot be declared to be a function"); |
904 | 1 |
dsym.type = Type.terror; |
905 | 1 |
tb = dsym.type; |
906 |
}
|
|
907 | 1 |
if (auto ts = tb.isTypeStruct()) |
908 |
{
|
|
909 | 1 |
if (!ts.sym.members) |
910 |
{
|
|
911 | 1 |
dsym.error("no definition of struct `%s`", ts.toChars()); |
912 |
}
|
|
913 |
}
|
|
914 | 1 |
if ((dsym.storage_class & STC.auto_) && !inferred) |
915 | 1 |
dsym.error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?"); |
916 |
|
|
917 | 1 |
if (auto tt = tb.isTypeTuple()) |
918 |
{
|
|
919 |
/* Instead, declare variables for each of the tuple elements
|
|
920 |
* and add those.
|
|
921 |
*/
|
|
922 | 1 |
size_t nelems = Parameter.dim(tt.arguments); |
923 | 1 |
Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression() : null; |
924 | 1 |
if (ie) |
925 | 1 |
ie = ie.expressionSemantic(sc); |
926 | 1 |
if (nelems > 0 && ie) |
927 |
{
|
|
928 | 1 |
auto iexps = new Expressions(); |
929 | 1 |
iexps.push(ie); |
930 | 1 |
auto exps = new Expressions(); |
931 | 1 |
for (size_t pos = 0; pos < iexps.dim; pos++) |
932 |
{
|
|
933 |
Lexpand1: |
|
934 | 1 |
Expression e = (*iexps)[pos]; |
935 | 1 |
Parameter arg = Parameter.getNth(tt.arguments, pos); |
936 | 1 |
arg.type = arg.type.typeSemantic(dsym.loc, sc); |
937 |
//printf("[%d] iexps.dim = %d, ", pos, iexps.dim);
|
|
938 |
//printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
|
|
939 |
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
|
|
940 |
|
|
941 | 1 |
if (e != ie) |
942 |
{
|
|
943 | 1 |
if (iexps.dim > nelems) |
944 |
goto Lnomatch; |
|
945 | 1 |
if (e.type.implicitConvTo(arg.type)) |
946 | 1 |
continue; |
947 |
}
|
|
948 |
|
|
949 | 1 |
if (e.op == TOK.tuple) |
950 |
{
|
|
951 | 1 |
TupleExp te = cast(TupleExp)e; |
952 | 1 |
if (iexps.dim - 1 + te.exps.dim > nelems) |
953 |
goto Lnomatch; |
|
954 |
|
|
955 | 1 |
iexps.remove(pos); |
956 | 1 |
iexps.insert(pos, te.exps); |
957 | 1 |
(*iexps)[pos] = Expression.combine(te.e0, (*iexps)[pos]); |
958 | 1 |
goto Lexpand1; |
959 |
}
|
|
960 | 1 |
else if (isAliasThisTuple(e)) |
961 |
{
|
|
962 | 1 |
auto v = copyToTemp(0, "__tup", e); |
963 | 1 |
v.dsymbolSemantic(sc); |
964 | 1 |
auto ve = new VarExp(dsym.loc, v); |
965 | 1 |
ve.type = e.type; |
966 |
|
|
967 | 1 |
exps.setDim(1); |
968 | 1 |
(*exps)[0] = ve; |
969 | 1 |
expandAliasThisTuples(exps, 0); |
970 |
|
|
971 | 1 |
for (size_t u = 0; u < exps.dim; u++) |
972 |
{
|
|
973 |
Lexpand2: |
|
974 | 1 |
Expression ee = (*exps)[u]; |
975 | 1 |
arg = Parameter.getNth(tt.arguments, pos + u); |
976 | 1 |
arg.type = arg.type.typeSemantic(dsym.loc, sc); |
977 |
//printf("[%d+%d] exps.dim = %d, ", pos, u, exps.dim);
|
|
978 |
//printf("ee = (%s %s, %s), ", Token::tochars[ee.op], ee.toChars(), ee.type.toChars());
|
|
979 |
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
|
|
980 |
|
|
981 | 1 |
size_t iexps_dim = iexps.dim - 1 + exps.dim; |
982 | 1 |
if (iexps_dim > nelems) |
983 |
goto Lnomatch; |
|
984 | 1 |
if (ee.type.implicitConvTo(arg.type)) |
985 | 1 |
continue; |
986 |
|
|
987 | 1 |
if (expandAliasThisTuples(exps, u) != -1) |
988 | 1 |
goto Lexpand2; |
989 |
}
|
|
990 |
|
|
991 | 1 |
if ((*exps)[0] != ve) |
992 |
{
|
|
993 | 1 |
Expression e0 = (*exps)[0]; |
994 | 1 |
(*exps)[0] = new CommaExp(dsym.loc, new DeclarationExp(dsym.loc, v), e0); |
995 | 1 |
(*exps)[0].type = e0.type; |
996 |
|
|
997 | 1 |
iexps.remove(pos); |
998 | 1 |
iexps.insert(pos, exps); |
999 | 1 |
goto Lexpand1; |
1000 |
}
|
|
1001 |
}
|
|
1002 |
}
|
|
1003 | 1 |
if (iexps.dim < nelems) |
1004 | 1 |
goto Lnomatch; |
1005 |
|
|
1006 | 1 |
ie = new TupleExp(dsym._init.loc, iexps); |
1007 |
}
|
|
1008 |
Lnomatch: |
|
1009 |
|
|
1010 | 1 |
if (ie && ie.op == TOK.tuple) |
1011 |
{
|
|
1012 | 1 |
TupleExp te = cast(TupleExp)ie; |
1013 | 1 |
size_t tedim = te.exps.dim; |
1014 | 1 |
if (tedim != nelems) |
1015 |
{
|
|
1016 |
error(dsym.loc, "tuple of %d elements cannot be assigned to tuple of %d elements", cast(int)tedim, cast(int)nelems); |
|
1017 |
for (size_t u = tedim; u < nelems; u++) // fill dummy expression |
|
1018 |
te.exps.push(ErrorExp.get()); |
|
1019 |
}
|
|
1020 |
}
|
|
1021 |
|
|
1022 | 1 |
auto exps = new Objects(nelems); |
1023 | 1 |
for (size_t i = 0; i < nelems; i++) |
1024 |
{
|
|
1025 | 1 |
Parameter arg = Parameter.getNth(tt.arguments, i); |
1026 |
|
|
1027 | 1 |
OutBuffer buf; |
1028 | 1 |
buf.printf("__%s_field_%llu", dsym.ident.toChars(), cast(ulong)i); |
1029 | 1 |
auto id = Identifier.idPool(buf[]); |
1030 |
|
|
1031 | 1 |
Initializer ti; |
1032 | 1 |
if (ie) |
1033 |
{
|
|
1034 | 1 |
Expression einit = ie; |
1035 | 1 |
if (ie.op == TOK.tuple) |
1036 |
{
|
|
1037 | 1 |
TupleExp te = cast(TupleExp)ie; |
1038 | 1 |
einit = (*te.exps)[i]; |
1039 | 1 |
if (i == 0) |
1040 | 1 |
einit = Expression.combine(te.e0, einit); |
1041 |
}
|
|
1042 | 1 |
ti = new ExpInitializer(einit.loc, einit); |
1043 |
}
|
|
1044 |
else
|
|
1045 | 1 |
ti = dsym._init ? dsym._init.syntaxCopy() : null; |
1046 |
|
|
1047 | 1 |
StorageClass storage_class = STC.temp | dsym.storage_class; |
1048 | 1 |
if ((dsym.storage_class & STC.parameter) && (arg.storageClass & STC.parameter)) |
1049 | 1 |
storage_class |= arg.storageClass; |
1050 | 1 |
auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class); |
1051 |
//printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars());
|
|
1052 | 1 |
v.dsymbolSemantic(sc); |
1053 |
|
|
1054 | 1 |
if (sc.scopesym) |
1055 |
{
|
|
1056 |
//printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars());
|
|
1057 | 1 |
if (sc.scopesym.members) |
1058 |
// Note this prevents using foreach() over members, because the limits can change
|
|
1059 | 1 |
sc.scopesym.members.push(v); |
1060 |
}
|
|
1061 |
|
|
1062 | 1 |
Expression e = new DsymbolExp(dsym.loc, v); |
1063 | 1 |
(*exps)[i] = e; |
1064 |
}
|
|
1065 | 1 |
auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps); |
1066 | 1 |
v2.parent = dsym.parent; |
1067 | 1 |
v2.isexp = true; |
1068 | 1 |
dsym.aliassym = v2; |
1069 | 1 |
dsym.semanticRun = PASS.semanticdone; |
1070 | 1 |
return; |
1071 |
}
|
|
1072 |
|
|
1073 |
/* Storage class can modify the type
|
|
1074 |
*/
|
|
1075 | 1 |
dsym.type = dsym.type.addStorageClass(dsym.storage_class); |
1076 |
|
|
1077 |
/* Adjust storage class to reflect type
|
|
1078 |
*/
|
|
1079 | 1 |
if (dsym.type.isConst()) |
1080 |
{
|
|
1081 | 1 |
dsym.storage_class |= STC.const_; |
1082 | 1 |
if (dsym.type.isShared()) |
1083 | 1 |
dsym.storage_class |= STC.shared_; |
1084 |
}
|
|
1085 | 1 |
else if (dsym.type.isImmutable()) |
1086 | 1 |
dsym.storage_class |= STC.immutable_; |
1087 | 1 |
else if (dsym.type.isShared()) |
1088 | 1 |
dsym.storage_class |= STC.shared_; |
1089 | 1 |
else if (dsym.type.isWild()) |
1090 | 1 |
dsym.storage_class |= STC.wild; |
1091 |
|
|
1092 | 1 |
if (StorageClass stc = dsym.storage_class & (STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_)) |
1093 |
{
|
|
1094 | 1 |
if (stc == STC.final_) |
1095 | 1 |
dsym.error("cannot be `final`, perhaps you meant `const`?"); |
1096 |
else
|
|
1097 |
{
|
|
1098 | 1 |
OutBuffer buf; |
1099 | 1 |
stcToBuffer(&buf, stc); |
1100 | 1 |
dsym.error("cannot be `%s`", buf.peekChars()); |
1101 |
}
|
|
1102 | 1 |
dsym.storage_class &= ~stc; // strip off |
1103 |
}
|
|
1104 |
|
|
1105 |
// At this point we can add `scope` to the STC instead of `in`,
|
|
1106 |
// because we are never going to use this variable's STC for user messages
|
|
1107 | 1 |
if (dsym.storage_class & STC.in_ && global.params.previewIn) |
1108 | 1 |
dsym.storage_class |= STC.scope_; |
1109 |
|
|
1110 | 1 |
if (dsym.storage_class & STC.scope_) |
1111 |
{
|
|
1112 | 1 |
StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.tls | STC.gshared); |
1113 | 1 |
if (stc) |
1114 |
{
|
|
1115 | 1 |
OutBuffer buf; |
1116 | 1 |
stcToBuffer(&buf, stc); |
1117 | 1 |
dsym.error("cannot be `scope` and `%s`", buf.peekChars()); |
1118 |
}
|
|
1119 | 1 |
else if (dsym.isMember()) |
1120 |
{
|
|
1121 | 1 |
dsym.error("field cannot be `scope`"); |
1122 |
}
|
|
1123 | 1 |
else if (!dsym.type.hasPointers()) |
1124 |
{
|
|
1125 | 1 |
dsym.storage_class &= ~STC.scope_; // silently ignore; may occur in generic code |
1126 |
}
|
|
1127 |
}
|
|
1128 |
|
|
1129 | 1 |
if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe)) |
1130 |
{
|
|
1131 |
}
|
|
1132 |
else
|
|
1133 |
{
|
|
1134 | 1 |
AggregateDeclaration aad = parent.isAggregateDeclaration(); |
1135 | 1 |
if (aad) |
1136 |
{
|
|
1137 | 1 |
if (global.params.vfield && dsym.storage_class & (STC.const_ | STC.immutable_) && dsym._init && !dsym._init.isVoidInitializer()) |
1138 |
{
|
|
1139 | 1 |
const(char)* s = (dsym.storage_class & STC.immutable_) ? "immutable" : "const"; |
1140 | 1 |
message(dsym.loc, "`%s.%s` is `%s` field", ad.toPrettyChars(), dsym.toChars(), s); |
1141 |
}
|
|
1142 | 1 |
dsym.storage_class |= STC.field; |
1143 | 1 |
if (auto ts = tbn.isTypeStruct()) |
1144 | 1 |
if (ts.sym.noDefaultCtor) |
1145 |
{
|
|
1146 | 1 |
if (!dsym.isThisDeclaration() && !dsym._init) |
1147 | 1 |
aad.noDefaultCtor = true; |
1148 |
}
|
|
1149 |
}
|
|
1150 |
|
|
1151 | 1 |
InterfaceDeclaration id = parent.isInterfaceDeclaration(); |
1152 | 1 |
if (id) |
1153 |
{
|
|
1154 | 1 |
dsym.error("field not allowed in interface"); |
1155 |
}
|
|
1156 | 1 |
else if (aad && aad.sizeok == Sizeok.done) |
1157 |
{
|
|
1158 | 1 |
dsym.error("cannot be further field because it will change the determined %s size", aad.toChars()); |
1159 |
}
|
|
1160 |
|
|
1161 |
/* Templates cannot add fields to aggregates
|
|
1162 |
*/
|
|
1163 | 1 |
TemplateInstance ti = parent.isTemplateInstance(); |
1164 | 1 |
if (ti) |
1165 |
{
|
|
1166 |
// Take care of nested templates
|
|
1167 | 1 |
while (1) |
1168 |
{
|
|
1169 | 1 |
TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); |
1170 | 1 |
if (!ti2) |
1171 | 1 |
break; |
1172 | 1 |
ti = ti2; |
1173 |
}
|
|
1174 |
// If it's a member template
|
|
1175 | 1 |
AggregateDeclaration ad2 = ti.tempdecl.isMember(); |
1176 | 1 |
if (ad2 && dsym.storage_class != STC.undefined_) |
1177 |
{
|
|
1178 | 1 |
dsym.error("cannot use template to add field to aggregate `%s`", ad2.toChars()); |
1179 |
}
|
|
1180 |
}
|
|
1181 |
}
|
|
1182 |
|
|
1183 | 1 |
if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This) |
1184 |
{
|
|
1185 | 1 |
dsym.error("only parameters or `foreach` declarations can be `ref`"); |
1186 |
}
|
|
1187 |
|
|
1188 | 1 |
if (dsym.type.hasWild()) |
1189 |
{
|
|
1190 | 1 |
if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg()) |
1191 |
{
|
|
1192 | 1 |
dsym.error("only parameters or stack based variables can be `inout`"); |
1193 |
}
|
|
1194 | 1 |
FuncDeclaration func = sc.func; |
1195 | 1 |
if (func) |
1196 |
{
|
|
1197 | 1 |
if (func.fes) |
1198 | 1 |
func = func.fes.func; |
1199 | 1 |
bool isWild = false; |
1200 | 1 |
for (FuncDeclaration fd = func; fd; fd = fd.toParentDecl().isFuncDeclaration()) |
1201 |
{
|
|
1202 | 1 |
if ((cast(TypeFunction)fd.type).iswild) |
1203 |
{
|
|
1204 | 1 |
isWild = true; |
1205 | 1 |
break; |
1206 |
}
|
|
1207 |
}
|
|
1208 | 1 |
if (!isWild) |
1209 |
{
|
|
1210 | 1 |
dsym.error("`inout` variables can only be declared inside `inout` functions"); |
1211 |
}
|
|
1212 |
}
|
|
1213 |
}
|
|
1214 |
|
|
1215 | 1 |
if (!(dsym.storage_class & (STC.ctfe | STC.ref_ | STC.result)) && |
1216 | 1 |
tbn.ty == Tstruct && (cast(TypeStruct)tbn).sym.noDefaultCtor) |
1217 |
{
|
|
1218 | 1 |
if (!dsym._init) |
1219 |
{
|
|
1220 | 1 |
if (dsym.isField()) |
1221 |
{
|
|
1222 |
/* For fields, we'll check the constructor later to make sure it is initialized
|
|
1223 |
*/
|
|
1224 | 1 |
dsym.storage_class |= STC.nodefaultctor; |
1225 |
}
|
|
1226 | 1 |
else if (dsym.storage_class & STC.parameter) |
1227 |
{
|
|
1228 |
}
|
|
1229 |
else
|
|
1230 | 1 |
dsym.error("default construction is disabled for type `%s`", dsym.type.toChars()); |
1231 |
}
|
|
1232 |
}
|
|
1233 |
|
|
1234 | 1 |
FuncDeclaration fd = parent.isFuncDeclaration(); |
1235 | 1 |
if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor)) |
1236 |
{
|
|
1237 | 1 |
if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.tls | STC.gshared) || !fd) |
1238 |
{
|
|
1239 |
dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`"); |
|
1240 |
}
|
|
1241 |
|
|
1242 |
// @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
|
|
1243 |
// Deprecated in 2.087
|
|
1244 |
// Remove this when the feature is removed from the language
|
|
1245 | 1 |
if (0 && // deprecation disabled for now to accommodate existing extensive use |
1246 |
!(dsym.storage_class & STC.scope_)) |
|
1247 |
{
|
|
1248 |
if (!(dsym.storage_class & STC.parameter) && dsym.ident != Id.withSym) |
|
1249 |
dsym.error("reference to `scope class` must be `scope`"); |
|
1250 |
}
|
|
1251 |
}
|
|
1252 |
|
|
1253 |
// Calculate type size + safety checks
|
|
1254 | 1 |
if (sc.func && !sc.intypeof) |
1255 |
{
|
|
1256 | 1 |
if (dsym._init && dsym._init.isVoidInitializer() && dsym.type.hasPointers()) // get type size |
1257 |
{
|
|
1258 | 1 |
if (sc.func.setUnsafe()) |
1259 | 1 |
dsym.error("`void` initializers for pointers not allowed in safe functions"); |
1260 |
}
|
|
1261 | 1 |
else if (!dsym._init && |
1262 | 1 |
!(dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field | STC.parameter)) && |
1263 | 1 |
dsym.type.hasVoidInitPointers()) |
1264 |
{
|
|
1265 | 1 |
if (sc.func.setUnsafe()) |
1266 | 1 |
dsym.error("`void` initializers for pointers not allowed in safe functions"); |
1267 |
}
|
|
1268 |
}
|
|
1269 |
|
|
1270 | 1 |
if ((!dsym._init || dsym._init.isVoidInitializer) && !fd) |
1271 |
{
|
|
1272 |
// If not mutable, initializable by constructor only
|
|
1273 | 1 |
dsym.storage_class |= STC.ctorinit; |
1274 |
}
|
|
1275 |
|
|
1276 | 1 |
if (dsym._init) |
1277 | 1 |
dsym.storage_class |= STC.init; // remember we had an explicit initializer |
1278 | 1 |
else if (dsym.storage_class & STC.manifest) |
1279 |
dsym.error("manifest constants must have initializers"); |
|
1280 |
|
|
1281 | 1 |
bool isBlit = false; |
1282 | 1 |
d_uns64 sz; |
1283 | 1 |
if (!dsym._init && |
1284 | 1 |
!(dsym.storage_class & (STC.static_ | STC.gshared | STC.extern_)) && |
1285 | 1 |
fd && |
1286 | 1 |
(!(dsym.storage_class & (STC.field | STC.in_ | STC.foreach_ | STC.parameter | STC.result)) || |
1287 | 1 |
(dsym.storage_class & STC.out_)) && |
1288 | 1 |
(sz = dsym.type.size()) != 0) |
1289 |
{
|
|
1290 |
// Provide a default initializer
|
|
1291 |
|
|
1292 |
//printf("Providing default initializer for '%s'\n", toChars());
|
|
1293 | 1 |
if (sz == SIZE_INVALID && dsym.type.ty != Terror) |
1294 | 1 |
dsym.error("size of type `%s` is invalid", dsym.type.toChars()); |
1295 |
|
|
1296 | 1 |
Type tv = dsym.type; |
1297 | 1 |
while (tv.ty == Tsarray) // Don't skip Tenum |
1298 | 1 |
tv = tv.nextOf(); |
1299 | 1 |
if (tv.needsNested()) |
1300 |
{
|
|
1301 |
/* Nested struct requires valid enclosing frame pointer.
|
|
1302 |
* In StructLiteralExp::toElem(), it's calculated.
|
|
1303 |
*/
|
|
1304 | 1 |
assert(tbn.ty == Tstruct); |
1305 | 1 |
checkFrameAccess(dsym.loc, sc, tbn.isTypeStruct().sym); |
1306 |
|
|
1307 | 1 |
Expression e = tv.defaultInitLiteral(dsym.loc); |
1308 | 1 |
e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e); |
1309 | 1 |
e = e.expressionSemantic(sc); |
1310 | 1 |
dsym._init = new ExpInitializer(dsym.loc, e); |
1311 | 1 |
goto Ldtor; |
1312 |
}
|
|
1313 | 1 |
if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.zeroInit) |
1314 |
{
|
|
1315 |
/* If a struct is all zeros, as a special case
|
|
1316 |
* set it's initializer to the integer 0.
|
|
1317 |
* In AssignExp::toElem(), we check for this and issue
|
|
1318 |
* a memset() to initialize the struct.
|
|
1319 |
* Must do same check in interpreter.
|
|
1320 |
*/
|
|
1321 | 1 |
Expression e = IntegerExp.literal!0; |
1322 | 1 |
e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e); |
1323 | 1 |
e.type = dsym.type; // don't type check this, it would fail |
1324 | 1 |
dsym._init = new ExpInitializer(dsym.loc, e); |
1325 | 1 |
goto Ldtor; |
1326 |
}
|
|
1327 | 1 |
if (dsym.type.baseElemOf().ty == Tvoid) |
1328 |
{
|
|
1329 | 1 |
dsym.error("`%s` does not have a default initializer", dsym.type.toChars()); |
1330 |
}
|
|
1331 | 1 |
else if (auto e = dsym.type.defaultInit(dsym.loc)) |
1332 |
{
|
|
1333 | 1 |
dsym._init = new ExpInitializer(dsym.loc, e); |
1334 |
}
|
|
1335 |
|
|
1336 |
// Default initializer is always a blit
|
|
1337 | 1 |
isBlit = true; |
1338 |
}
|
|
1339 | 1 |
if (dsym._init) |
1340 |
{
|
|
1341 | 1 |
sc = sc.push(); |
1342 | 1 |
sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable); |
1343 |
|
|
1344 | 1 |
ExpInitializer ei = dsym._init.isExpInitializer(); |
1345 | 1 |
if (ei) // https://issues.dlang.org/show_bug.cgi?id=13424 |
1346 |
// Preset the required type to fail in FuncLiteralDeclaration::semantic3
|
|
1347 | 1 |
ei.exp = inferType(ei.exp, dsym.type); |
1348 |
|
|
1349 |
// If inside function, there is no semantic3() call
|
|
1350 | 1 |
if (sc.func || sc.intypeof == 1) |
1351 |
{
|
|
1352 |
// If local variable, use AssignExp to handle all the various
|
|
1353 |
// possibilities.
|
|
1354 | 1 |
if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.tls | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer()) |
1355 |
{
|
|
1356 |
//printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars());
|
|
1357 | 1 |
if (!ei) |
1358 |
{
|
|
1359 | 1 |
ArrayInitializer ai = dsym._init.isArrayInitializer(); |
1360 | 1 |
Expression e; |
1361 | 1 |
if (ai && tb.ty == Taarray) |
1362 | 1 |
e = ai.toAssocArrayLiteral(); |
1363 |
else
|
|
1364 | 1 |
e = dsym._init.initializerToExpression(); |
1365 | 1 |
if (!e) |
1366 |
{
|
|
1367 |
// Run semantic, but don't need to interpret
|
|
1368 | 1 |
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret); |
1369 | 1 |
e = dsym._init.initializerToExpression(); |
1370 | 1 |
if (!e) |
1371 |
{
|
|
1372 |
dsym.error("is not a static and cannot have static initializer"); |
|
1373 |
e = ErrorExp.get(); |
|
1374 |
}
|
|
1375 |
}
|
|
1376 | 1 |
ei = new ExpInitializer(dsym._init.loc, e); |
1377 | 1 |
dsym._init = ei; |
1378 |
}
|
|
1379 |
|
|
1380 | 1 |
Expression exp = ei.exp; |
1381 | 1 |
Expression e1 = new VarExp(dsym.loc, dsym); |
1382 | 1 |
if (isBlit) |
1383 | 1 |
exp = new BlitExp(dsym.loc, e1, exp); |
1384 |
else
|
|
1385 | 1 |
exp = new ConstructExp(dsym.loc, e1, exp); |
1386 | 1 |
dsym.canassign++; |
1387 | 1 |
exp = exp.expressionSemantic(sc); |
1388 | 1 |
dsym.canassign--; |
1389 | 1 |
exp = exp.optimize(WANTvalue); |
1390 | 1 |
if (exp.op == TOK.error) |
1391 |
{
|
|
1392 | 1 |
dsym._init = new ErrorInitializer(); |
1393 | 1 |
ei = null; |
1394 |
}
|
|
1395 |
else
|
|
1396 | 1 |
ei.exp = exp; |
1397 |
|
|
1398 | 1 |
if (ei && dsym.isScope()) |
1399 |
{
|
|
1400 | 1 |
Expression ex = ei.exp.lastComma(); |
1401 | 1 |
if (ex.op == TOK.blit || ex.op == TOK.construct) |
1402 | 1 |
ex = (cast(AssignExp)ex).e2; |
1403 | 1 |
if (ex.op == TOK.new_) |
1404 |
{
|
|
1405 |
// See if initializer is a NewExp that can be allocated on the stack
|
|
1406 | 1 |
NewExp ne = cast(NewExp)ex; |
1407 | 1 |
if (dsym.type.toBasetype().ty == Tclass) |
1408 |
{
|
|
1409 | 1 |
if (ne.newargs && ne.newargs.dim > 1) |
1410 |
{
|
|
1411 |
dsym.mynew = true; |
|
1412 |
}
|
|
1413 |
else
|
|
1414 |
{
|
|
1415 | 1 |
ne.onstack = 1; |
1416 | 1 |
dsym.onstack = true; |
1417 |
}
|
|
1418 |
}
|
|
1419 |
}
|
|
1420 | 1 |
else if (ex.op == TOK.function_) |
1421 |
{
|
|
1422 |
// or a delegate that doesn't escape a reference to the function
|
|
1423 | 1 |
FuncDeclaration f = (cast(FuncExp)ex).fd; |
1424 | 1 |
if (f.tookAddressOf) |
1425 |
f.tookAddressOf--; |
|
1426 |
}
|
|
1427 |
}
|
|
1428 |
}
|
|
1429 |
else
|
|
1430 |
{
|
|
1431 |
// https://issues.dlang.org/show_bug.cgi?id=14166
|
|
1432 |
// Don't run CTFE for the temporary variables inside typeof
|
|
1433 | 1 |
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); |
1434 | 1 |
const init_err = dsym._init.isExpInitializer(); |
1435 | 1 |
if (init_err && init_err.exp.op == TOK.showCtfeContext) |
1436 |
{
|
|
1437 | 1 |
errorSupplemental(dsym.loc, "compile time context created here"); |
1438 |
}
|
|
1439 |
}
|
|
1440 |
}
|
|
1441 | 1 |
else if (parent.isAggregateDeclaration()) |
1442 |
{
|
|
1443 | 1 |
dsym._scope = scx ? scx : sc.copy(); |
1444 | 1 |
dsym._scope.setNoFree(); |
1445 |
}
|
|
1446 | 1 |
else if (dsym.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) || dsym.type.isConst() || dsym.type.isImmutable()) |
1447 |
{
|
|
1448 |
/* Because we may need the results of a const declaration in a
|
|
1449 |
* subsequent type, such as an array dimension, before semantic2()
|
|
1450 |
* gets ordinarily run, try to run semantic2() now.
|
|
1451 |
* Ignore failure.
|
|
1452 |
*/
|
|
1453 | 1 |
if (!inferred) |
1454 |
{
|
|
1455 | 1 |
uint errors = global.errors; |
1456 | 1 |
dsym.inuse++; |
1457 |
// Bug 20549. Don't try this on modules or packages, syntaxCopy
|
|
1458 |
// could crash (inf. recursion) on a mod/pkg referencing itself
|
|
1459 | 1 |
if (ei && (ei.exp.op != TOK.scope_ ? true : !(cast(ScopeExp)ei.exp).sds.isPackage())) |
1460 |
{
|
|
1461 | 1 |
Expression exp = ei.exp.syntaxCopy(); |
1462 |
|
|
1463 | 1 |
bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest); |
1464 | 1 |
if (needctfe) |
1465 | 1 |
sc = sc.startCTFE(); |
1466 | 1 |
exp = exp.expressionSemantic(sc); |
1467 | 1 |
exp = resolveProperties(sc, exp); |
1468 | 1 |
if (needctfe) |
1469 | 1 |
sc = sc.endCTFE(); |
1470 |
|
|
1471 | 1 |
Type tb2 = dsym.type.toBasetype(); |
1472 | 1 |
Type ti = exp.type.toBasetype(); |
1473 |
|
|
1474 |
/* The problem is the following code:
|
|
1475 |
* struct CopyTest {
|
|
1476 |
* double x;
|
|
1477 |
* this(double a) { x = a * 10.0;}
|
|
1478 |
* this(this) { x += 2.0; }
|
|
1479 |
* }
|
|
1480 |
* const CopyTest z = CopyTest(5.3); // ok
|
|
1481 |
* const CopyTest w = z; // not ok, postblit not run
|
|
1482 |
* static assert(w.x == 55.0);
|
|
1483 |
* because the postblit doesn't get run on the initialization of w.
|
|
1484 |
*/
|
|
1485 | 1 |
if (auto ts = ti.isTypeStruct()) |
1486 |
{
|
|
1487 | 1 |
StructDeclaration sd = ts.sym; |
1488 |
/* Look to see if initializer involves a copy constructor
|
|
1489 |
* (which implies a postblit)
|
|
1490 |
*/
|
|
1491 |
// there is a copy constructor
|
|
1492 |
// and exp is the same struct
|
|
1493 | 1 |
if (sd.postblit && tb2.toDsymbol(null) == sd) |
1494 |
{
|
|
1495 |
// The only allowable initializer is a (non-copy) constructor
|
|
1496 | 1 |
if (exp.isLvalue()) |
1497 | 1 |
dsym.error("of type struct `%s` uses `this(this)`, which is not allowed in static initialization", tb2.toChars()); |
1498 |
}
|
|
1499 |
}
|
|
1500 | 1 |
ei.exp = exp; |
1501 |
}
|
|
1502 | 1 |
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret); |
1503 | 1 |
dsym.inuse--; |
1504 | 1 |
if (global.errors > errors) |
1505 |
{
|
|
1506 | 1 |
dsym._init = new ErrorInitializer(); |
1507 | 1 |
dsym.type = Type.terror; |
1508 |
}
|
|
1509 |
}
|
|
1510 |
else
|
|
1511 |
{
|
|
1512 | 1 |
dsym._scope = scx ? scx : sc.copy(); |
1513 | 1 |
dsym._scope.setNoFree(); |
1514 |
}
|
|
1515 |
}
|
|
1516 | 1 |
sc = sc.pop(); |
1517 |
}
|
|
1518 |
|
|
1519 |
Ldtor: |
|
1520 |
/* Build code to execute destruction, if necessary
|
|
1521 |
*/
|
|
1522 | 1 |
dsym.edtor = dsym.callScopeDtor(sc); |
1523 | 1 |
if (dsym.edtor) |
1524 |
{
|
|
1525 |
/* If dsym is a local variable, who's type is a struct with a scope destructor,
|
|
1526 |
* then make dsym scope, too.
|
|
1527 |
*/
|
|
1528 | 1 |
if (global.params.vsafe && |
1529 | 1 |
!(dsym.storage_class & (STC.parameter | STC.temp | STC.field | STC.in_ | STC.foreach_ | STC.result | STC.manifest)) && |
1530 | 1 |
!dsym.isDataseg() && |
1531 | 1 |
!dsym.doNotInferScope && |
1532 | 1 |
dsym.type.hasPointers()) |
1533 |
{
|
|
1534 | 1 |
auto tv = dsym.type.baseElemOf(); |
1535 | 1 |
if (tv.ty == Tstruct && |
1536 | 1 |
(cast(TypeStruct)tv).sym.dtor.storage_class & STC.scope_) |
1537 |
{
|
|
1538 | 1 |
dsym.storage_class |= STC.scope_; |
1539 |
}
|
|
1540 |
}
|
|
1541 |
|
|
1542 | 1 |
if (sc.func && dsym.storage_class & (STC.static_ | STC.gshared)) |
1543 | 1 |
dsym.edtor = dsym.edtor.expressionSemantic(sc._module._scope); |
1544 |
else
|
|
1545 | 1 |
dsym.edtor = dsym.edtor.expressionSemantic(sc); |
1546 |
|
|
1547 |
version (none) |
|
1548 |
{
|
|
1549 |
// currently disabled because of std.stdio.stdin, stdout and stderr
|
|
1550 |
if (dsym.isDataseg() && !(dsym.storage_class & STC.extern_)) |
|
1551 |
dsym.error("static storage variables cannot have destructors"); |
|
1552 |
}
|
|
1553 |
}
|
|
1554 |
|
|
1555 | 1 |
dsym.semanticRun = PASS.semanticdone; |
1556 |
|
|
1557 | 1 |
if (dsym.type.toBasetype().ty == Terror) |
1558 | 1 |
dsym.errors = true; |
1559 |
|
|
1560 | 1 |
if(sc.scopesym && !sc.scopesym.isAggregateDeclaration()) |
1561 |
{
|
|
1562 | 1 |
for (ScopeDsymbol sym = sc.scopesym; sym && dsym.endlinnum == 0; |
1563 | 1 |
sym = sym.parent ? sym.parent.isScopeDsymbol() : null) |
1564 | 1 |
dsym.endlinnum = sym.endlinnum; |
1565 |
}
|
|
1566 |
}
|
|
1567 |
|
|
1568 |
override void visit(TypeInfoDeclaration dsym) |
|
1569 |
{
|
|
1570 | 1 |
assert(dsym.linkage == LINK.c); |
1571 |
}
|
|
1572 |
|
|
1573 |
override void visit(Import imp) |
|
1574 |
{
|
|
1575 |
//printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars());
|
|
1576 | 1 |
if (imp.semanticRun > PASS.init) |
1577 | 1 |
return; |
1578 |
|
|
1579 | 1 |
if (imp._scope) |
1580 |
{
|
|
1581 | 1 |
sc = imp._scope; |
1582 | 1 |
imp._scope = null; |
1583 |
}
|
|
1584 | 1 |
if (!sc) |
1585 |
return; |
|
1586 |
|
|
1587 | 1 |
imp.semanticRun = PASS.semantic; |
1588 |
|
|
1589 |
// Load if not already done so
|
|
1590 | 1 |
bool loadErrored = false; |
1591 | 1 |
if (!imp.mod) |
1592 |
{
|
|
1593 | 1 |
loadErrored = imp.load(sc); |
1594 | 1 |
if (imp.mod) |
1595 |
{
|
|
1596 | 1 |
imp.mod.importAll(null); |
1597 | 1 |
imp.mod.checkImportDeprecation(imp.loc, sc); |
1598 |
}
|
|
1599 |
}
|
|
1600 | 1 |
if (imp.mod) |
1601 |
{
|
|
1602 |
// Modules need a list of each imported module
|
|
1603 |
|
|
1604 |
// if inside a template instantiation, the instantianting
|
|
1605 |
// module gets the import.
|
|
1606 |
// https://issues.dlang.org/show_bug.cgi?id=17181
|
|
1607 | 1 |
Module importer = sc._module; |
1608 | 1 |
if (sc.minst && sc.tinst) |
1609 |
{
|
|
1610 | 1 |
importer = sc.minst; |
1611 | 1 |
if (!sc.tinst.importedModules.contains(imp.mod)) |
1612 | 1 |
sc.tinst.importedModules.push(imp.mod); |
1613 |
}
|
|
1614 |
//printf("%s imports %s\n", importer.toChars(), imp.mod.toChars());
|
|
1615 | 1 |
if (!importer.aimports.contains(imp.mod)) |
1616 | 1 |
importer.aimports.push(imp.mod); |
1617 |
|
|
1618 | 1 |
if (sc.explicitProtection) |
1619 | 1 |
imp.protection = sc.protection; |
1620 |
|
|
1621 | 1 |
if (!imp.aliasId && !imp.names.dim) // neither a selective nor a renamed import |
1622 |
{
|
|
1623 | 1 |
ScopeDsymbol scopesym; |
1624 | 1 |
for (Scope* scd = sc; scd; scd = scd.enclosing) |
1625 |
{
|
|
1626 | 1 |
if (!scd.scopesym) |
1627 | 1 |
continue; |
1628 | 1 |
scopesym = scd.scopesym; |
1629 | 1 |
break; |
1630 |
}
|
|
1631 |
|
|
1632 | 1 |
if (!imp.isstatic) |
1633 |
{
|
|
1634 | 1 |
scopesym.importScope(imp.mod, imp.protection); |
1635 |
}
|
|
1636 |
|
|
1637 |
// Mark the imported packages as accessible from the current
|
|
1638 |
// scope. This access check is necessary when using FQN b/c
|
|
1639 |
// we're using a single global package tree.
|
|
1640 |
// https://issues.dlang.org/show_bug.cgi?id=313
|
|
1641 | 1 |
if (imp.packages) |
1642 |
{
|
|
1643 |
// import a.b.c.d;
|
|
1644 | 1 |
auto p = imp.pkg; // a |
1645 | 1 |
scopesym.addAccessiblePackage(p, imp.protection); |
1646 | 1 |
foreach (id; (*imp.packages)[1 .. imp.packages.dim]) // [b, c] |
1647 |
{
|
|
1648 | 1 |
p = cast(Package) p.symtab.lookup(id); |
1649 |
// https://issues.dlang.org/show_bug.cgi?id=17991
|
|
1650 |
// An import of truly empty file/package can happen
|
|
1651 |
// https://issues.dlang.org/show_bug.cgi?id=20151
|
|
1652 |
// Package in the path conflicts with a module name
|
|
1653 | 1 |
if (p is null) |
1654 | 1 |
break; |
1655 | 1 |
scopesym.addAccessiblePackage(p, imp.protection); |
1656 |
}
|
|
1657 |
}
|
|
1658 | 1 |
scopesym.addAccessiblePackage(imp.mod, imp.protection); // d |
1659 |
}
|
|
1660 |
|
|
1661 | 1 |
if (!loadErrored) |
1662 |
{
|
|
1663 | 1 |
imp.mod.dsymbolSemantic(null); |
1664 |
}
|
|
1665 |
|
|
1666 | 1 |
if (imp.mod.needmoduleinfo) |
1667 |
{
|
|
1668 |
//printf("module4 %s because of %s\n", importer.toChars(), imp.mod.toChars());
|
|
1669 | 1 |
importer.needmoduleinfo = 1; |
1670 |
}
|
|
1671 |
|
|
1672 | 1 |
sc = sc.push(imp.mod); |
1673 | 1 |
sc.protection = imp.protection; |
1674 | 1 |
for (size_t i = 0; i < imp.aliasdecls.dim; i++) |
1675 |
{
|
|
1676 | 1 |
AliasDeclaration ad = imp.aliasdecls[i]; |
1677 |
//printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope);
|
|
1678 | 1 |
Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports); |
1679 | 1 |
if (sym) |
1680 |
{
|
|
1681 |
import dmd.access : symbolIsVisible; |
|
1682 | 1 |
if (!symbolIsVisible(sc, sym)) |
1683 | 1 |
imp.mod.error(imp.loc, "member `%s` is not visible from module `%s`", |
1684 |
imp.names[i].toChars(), sc._module.toChars()); |
|
1685 | 1 |
ad.dsymbolSemantic(sc); |
1686 |
// If the import declaration is in non-root module,
|
|
1687 |
// analysis of the aliased symbol is deferred.
|
|
1688 |
// Therefore, don't see the ad.aliassym or ad.type here.
|
|
1689 |
}
|
|
1690 |
else
|
|
1691 |
{
|
|
1692 | 1 |
Dsymbol s = imp.mod.search_correct(imp.names[i]); |
1693 | 1 |
if (s) |
1694 | 1 |
imp.mod.error(imp.loc, "import `%s` not found, did you mean %s `%s`?", imp.names[i].toChars(), s.kind(), s.toPrettyChars()); |
1695 |
else
|
|
1696 | 1 |
imp.mod.error(imp.loc, "import `%s` not found", imp.names[i].toChars()); |
1697 | 1 |
ad.type = Type.terror; |
1698 |
}
|
|
1699 |
}
|
|
1700 | 1 |
sc = sc.pop(); |
1701 |
}
|
|
1702 |
|
|
1703 | 1 |
imp.semanticRun = PASS.semanticdone; |
1704 |
|
|
1705 |
// object self-imports itself, so skip that
|
|
1706 |
// https://issues.dlang.org/show_bug.cgi?id=7547
|
|
1707 |
// don't list pseudo modules __entrypoint.d, __main.d
|
|
1708 |
// https://issues.dlang.org/show_bug.cgi?id=11117
|
|
1709 |
// https://issues.dlang.org/show_bug.cgi?id=11164
|
|
1710 | 1 |
if (global.params.moduleDeps !is null && !(imp.id == Id.object && sc._module.ident == Id.object) && |
1711 | 1 |
strcmp(sc._module.ident.toChars(), "__main") != 0) |
1712 |
{
|
|
1713 |
/* The grammar of the file is:
|
|
1714 |
* ImportDeclaration
|
|
1715 |
* ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
|
|
1716 |
* ModuleAliasIdentifier ] "\n"
|
|
1717 |
*
|
|
1718 |
* BasicImportDeclaration
|
|
1719 |
* ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
|
|
1720 |
* " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
|
|
1721 |
*
|
|
1722 |
* FilePath
|
|
1723 |
* - any string with '(', ')' and '\' escaped with the '\' character
|
|
1724 |
*/
|
|
1725 | 1 |
OutBuffer* ob = global.params.moduleDeps; |
1726 | 1 |
Module imod = sc.instantiatingModule(); |
1727 | 1 |
if (!global.params.moduleDepsFile) |
1728 | 1 |
ob.writestring("depsImport "); |
1729 | 1 |
ob.writestring(imod.toPrettyChars()); |
1730 | 1 |
ob.writestring(" ("); |
1731 | 1 |
escapePath(ob, imod.srcfile.toChars()); |
1732 | 1 |
ob.writestring(") : "); |
1733 |
// use protection instead of sc.protection because it couldn't be
|
|
1734 |
// resolved yet, see the comment above
|
|
1735 | 1 |
protectionToBuffer(ob, imp.protection); |
1736 | 1 |
ob.writeByte(' '); |
1737 | 1 |
if (imp.isstatic) |
1738 |
{
|
|
1739 |
stcToBuffer(ob, STC.static_); |
|
1740 |
ob.writeByte(' '); |
|
1741 |
}
|
|
1742 | 1 |
ob.writestring(": "); |
1743 | 1 |
if (imp.packages) |
1744 |
{
|
|
1745 | 1 |
for (size_t i = 0; i < imp.packages.dim; i++) |
1746 |
{
|
|
1747 | 1 |
Identifier pid = (*imp.packages)[i]; |
1748 | 1 |
ob.printf("%s.", pid.toChars()); |
1749 |
}
|
|
1750 |
}
|
|
1751 | 1 |
ob.writestring(imp.id.toString()); |
1752 | 1 |
ob.writestring(" ("); |
1753 | 1 |
if (imp.mod) |
1754 | 1 |
escapePath(ob, imp.mod.srcfile.toChars()); |
1755 |
else
|
|
1756 |
ob.writestring("???"); |
|
1757 | 1 |
ob.writeByte(')'); |
1758 | 1 |
foreach (i, name; imp.names) |
1759 |
{
|
|
1760 | 1 |
if (i == 0) |
1761 | 1 |
ob.writeByte(':'); |
1762 |
else
|
|
1763 | 1 |
ob.writeByte(','); |
1764 | 1 |
Identifier _alias = imp.aliases[i]; |
1765 | 1 |
if (!_alias) |
1766 |
{
|
|
1767 | 1 |
ob.printf("%s", name.toChars()); |
1768 | 1 |
_alias = name; |
1769 |
}
|
|
1770 |
else
|
|
1771 |
ob.printf("%s=%s", _alias.toChars(), name.toChars()); |
|
1772 |
}
|
|
1773 | 1 |
if (imp.aliasId) |
1774 |
ob.printf(" -> %s", imp.aliasId.toChars()); |
|
1775 | 1 |
ob.writenl(); |
1776 |
}
|
|
1777 |
//printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
|
|
1778 |
}
|
|
1779 |
|
|
1780 |
void attribSemantic(AttribDeclaration ad) |
|
1781 |
{
|
|
1782 | 1 |
if (ad.semanticRun != PASS.init) |
1783 | 1 |
return; |
1784 | 1 |
ad.semanticRun = PASS.semantic; |
1785 | 1 |
Dsymbols* d = ad.include(sc); |
1786 |
//printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
|
|
1787 | 1 |
if (d) |
1788 |
{
|
|
1789 | 1 |
Scope* sc2 = ad.newScope(sc); |
1790 | 1 |
bool errors; |
1791 | 1 |
for (size_t i = 0; i < d.dim; i++) |
1792 |
{
|
|
1793 | 1 |
Dsymbol s = (*d)[i]; |
1794 | 1 |
s.dsymbolSemantic(sc2); |
1795 | 1 |
errors |= s.errors; |
1796 |
}
|
|
1797 | 1 |
ad.errors |= errors; |
1798 | 1 |
if (sc2 != sc) |
1799 | 1 |
sc2.pop(); |
1800 |
}
|
|
1801 | 1 |
ad.semanticRun = PASS.semanticdone; |
1802 |
}
|
|
1803 |
|
|
1804 |
override void visit(AttribDeclaration atd) |
|
1805 |
{
|
|
1806 | 1 |
attribSemantic(atd); |
1807 |
}
|
|
1808 |
|
|
1809 |
override void visit(AnonDeclaration scd) |
|
1810 |
{
|
|
1811 |
//printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
|
|
1812 | 1 |
assert(sc.parent); |
1813 | 1 |
auto p = sc.parent.pastMixin(); |
1814 | 1 |
auto ad = p.isAggregateDeclaration(); |
1815 | 1 |
if (!ad) |
1816 |
{
|
|
1817 | 1 |
error(scd.loc, "%s can only be a part of an aggregate, not %s `%s`", scd.kind(), p.kind(), p.toChars()); |
1818 | 1 |
scd.errors = true; |
1819 | 1 |
return; |
1820 |
}
|
|
1821 |
|
|
1822 | 1 |
if (scd.decl) |
1823 |
{
|
|
1824 | 1 |
sc = sc.push(); |
1825 | 1 |
sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.gshared); |
1826 | 1 |
sc.inunion = scd.isunion ? scd : null; |
1827 | 1 |
sc.flags = 0; |
1828 | 1 |
for (size_t i = 0; i < scd.decl.dim; i++) |
1829 |
{
|
|
1830 | 1 |
Dsymbol s = (*scd.decl)[i]; |
1831 | 1 |
s.dsymbolSemantic(sc); |
1832 |
}
|
|
1833 | 1 |
sc = sc.pop(); |
1834 |
}
|
|
1835 |
}
|
|
1836 |
|
|
1837 |
override void visit(PragmaDeclaration pd) |
|
1838 |
{
|
|
1839 |
// Should be merged with PragmaStatement
|
|
1840 |
//printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars());
|
|
1841 | 1 |
if (global.params.mscoff) |
1842 |
{
|
|
1843 |
if (pd.ident == Id.linkerDirective) |
|
1844 |
{
|
|
1845 |
if (!pd.args || pd.args.dim != 1) |
|
1846 |
pd.error("one string argument expected for pragma(linkerDirective)"); |
|
1847 |
else
|
|
1848 |
{
|
|
1849 |
auto se = semanticString(sc, (*pd.args)[0], "linker directive"); |
|
1850 |
if (!se) |
|
1851 |
goto Lnodecl; |
|
1852 |
(*pd.args)[0] = se; |
|
1853 |
if (global.params.verbose) |
|
1854 |
message("linkopt %.*s", cast(int)se.len, se.peekString().ptr); |
|
1855 |
}
|
|
1856 |
goto Lnodecl; |
|
1857 |
}
|
|
1858 |
}
|
|
1859 | 1 |
if (pd.ident == Id.msg) |
1860 |
{
|
|
1861 | 1 |
if (pd.args) |
1862 |
{
|
|
1863 | 1 |
for (size_t i = 0; i < pd.args.dim; i++) |
1864 |
{
|
|
1865 | 1 |
Expression e = (*pd.args)[i]; |
1866 | 1 |
sc = sc.startCTFE(); |
1867 | 1 |
e = e.expressionSemantic(sc); |
1868 | 1 |
e = resolveProperties(sc, e); |
1869 | 1 |
sc = sc.endCTFE(); |
1870 |
// pragma(msg) is allowed to contain types as well as expressions
|
|
1871 | 1 |
if (e.type && e.type.ty == Tvoid) |
1872 |
{
|
|
1873 | 1 |
error(pd.loc, "Cannot pass argument `%s` to `pragma msg` because it is `void`", e.toChars()); |
1874 | 1 |
return; |
1875 |
}
|
|
1876 | 1 |
e = ctfeInterpretForPragmaMsg(e); |
1877 | 1 |
if (e.op == TOK.error) |
1878 |
{
|
|
1879 | 1 |
errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars()); |
1880 | 1 |
return; |
1881 |
}
|
|
1882 | 1 |
StringExp se = e.toStringExp(); |
1883 | 1 |
if (se) |
1884 |
{
|
|
1885 | 1 |
se = se.toUTF8(sc); |
1886 | 1 |
fprintf(stderr, "%.*s", cast(int)se.len, se.peekString().ptr); |
1887 |
}
|
|
1888 |
else
|
|
1889 | 1 |
fprintf(stderr, "%s", e.toChars()); |
1890 |
}
|
|
1891 | 1 |
fprintf(stderr, "\n"); |
1892 |
}
|
|
1893 | 1 |
goto Lnodecl; |
1894 |
}
|
|
1895 | 1 |
else if (pd.ident == Id.lib) |
1896 |
{
|
|
1897 | 1 |
if (!pd.args || pd.args.dim != 1) |
1898 |
pd.error("string expected for library name"); |
|
1899 |
else
|
|
1900 |
{
|
|
1901 | 1 |
auto se = semanticString(sc, (*pd.args)[0], "library name"); |
1902 | 1 |
if (!se) |
1903 |
goto Lnodecl; |
|
1904 | 1 |
(*pd.args)[0] = se; |
1905 |
|
|
1906 | 1 |
auto name = se.peekString().xarraydup; |
1907 | 1 |
if (global.params.verbose) |
1908 |
message("library %s", name.ptr); |
|
1909 | 1 |
if (global.params.moduleDeps && !global.params.moduleDepsFile) |
1910 |
{
|
|
1911 |
OutBuffer* ob = global.params.moduleDeps; |
|
1912 |
Module imod = sc.instantiatingModule(); |
|
1913 |
ob.writestring("depsLib "); |
|
1914 |
ob.writestring(imod.toPrettyChars()); |
|
1915 |
ob.writestring(" ("); |
|
1916 |
escapePath(ob, imod.srcfile.toChars()); |
|
1917 |
ob.writestring(") : "); |
|
1918 |
ob.writestring(name); |
|
1919 |
ob.writenl(); |
|
1920 |
}
|
|
1921 | 1 |
mem.xfree(name.ptr); |
1922 |
}
|
|
1923 | 1 |
goto Lnodecl; |
1924 |
}
|
|
1925 | 1 |
else if (pd.ident == Id.startaddress) |
1926 |
{
|
|
1927 | 1 |
if (!pd.args || pd.args.dim != 1) |
1928 |
pd.error("function name expected for start address"); |
|
1929 |
else
|
|
1930 |
{
|
|
1931 |
/* https://issues.dlang.org/show_bug.cgi?id=11980
|
|
1932 |
* resolveProperties and ctfeInterpret call are not necessary.
|
|
1933 |
*/
|
|
1934 | 1 |
Expression e = (*pd.args)[0]; |
1935 | 1 |
sc = sc.startCTFE(); |
1936 | 1 |
e = e.expressionSemantic(sc); |
1937 | 1 |
sc = sc.endCTFE(); |
1938 | 1 |
(*pd.args)[0] = e; |
1939 | 1 |
Dsymbol sa = getDsymbol(e); |
1940 | 1 |
if (!sa || !sa.isFuncDeclaration()) |
1941 |
pd.error("function name expected for start address, not `%s`", e.toChars()); |
|
1942 |
}
|
|
1943 | 1 |
goto Lnodecl; |
1944 |
}
|
|
1945 | 1 |
else if (pd.ident == Id.Pinline) |
1946 |
{
|
|
1947 | 1 |
goto Ldecl; |
1948 |
}
|
|
1949 | 1 |
else if (pd.ident == Id.mangle) |
1950 |
{
|
|
1951 | 1 |
if (!pd.args) |
1952 | 1 |
pd.args = new Expressions(); |
1953 | 1 |
if (pd.args.dim != 1) |
1954 |
{
|
|
1955 | 1 |
pd.error("string expected for mangled name"); |
1956 | 1 |
pd.args.setDim(1); |
1957 | 1 |
(*pd.args)[0] = ErrorExp.get(); // error recovery |
1958 | 1 |
goto Ldecl; |
1959 |
}
|
|
1960 |
|
|
1961 | 1 |
auto se = semanticString(sc, (*pd.args)[0], "mangled name"); |
1962 | 1 |
if (!se) |
1963 | 1 |
goto Ldecl; |
1964 | 1 |
(*pd.args)[0] = se; // Will be used later |
1965 |
|
|
1966 | 1 |
if (!se.len) |
1967 |
{
|
|
1968 | 1 |
pd.error("zero-length string not allowed for mangled name"); |
1969 | 1 |
goto Ldecl; |
1970 |
}
|
|
1971 | 1 |
if (se.sz != 1) |
1972 |
{
|
|
1973 | 1 |
pd.error("mangled name characters can only be of type `char`"); |
1974 | 1 |
goto Ldecl; |
1975 |
}
|
|
1976 |
version (all) |
|
1977 |
{
|
|
1978 |
/* Note: D language specification should not have any assumption about backend
|
|
1979 |
* implementation. Ideally pragma(mangle) can accept a string of any content.
|
|
1980 |
*
|
|
1981 |
* Therefore, this validation is compiler implementation specific.
|
|
1982 |
*/
|
|
1983 | 1 |
auto slice = se.peekString(); |
1984 | 1 |
for (size_t i = 0; i < se.len;) |
1985 |
{
|
|
1986 | 1 |
dchar c = slice[i]; |
1987 | 1 |
if (c < 0x80) |
1988 |
{
|
|
1989 | 1 |
if (c.isValidMangling) |
1990 |
{
|
|
1991 | 1 |
++i; |
1992 | 1 |
continue; |
1993 |
}
|
|
1994 |
else
|
|
1995 |
{
|
|
1996 | 1 |
pd.error("char 0x%02x not allowed in mangled name", c); |
1997 | 1 |
break; |
1998 |
}
|
|
1999 |
}
|
|
2000 | 1 |
if (const msg = utf_decodeChar(slice, i, c)) |
2001 |
{
|
|
2002 | 1 |
pd.error("%.*s", cast(int)msg.length, msg.ptr); |
2003 | 1 |
break; |
2004 |
}
|
|
2005 | 1 |
if (!isUniAlpha(c)) |
2006 |
{
|
|
2007 |
pd.error("char `0x%04x` not allowed in mangled name", c); |
|
2008 |
break; |
|
2009 |
}
|
|
2010 |
}
|
|
2011 |
}
|
|
2012 |
}
|
|
2013 | 1 |
else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) |
2014 |
{
|
|
2015 | 1 |
if (pd.args && pd.args.dim != 0) |
2016 | 1 |
pd.error("takes no argument"); |
2017 | 1 |
goto Ldecl; |
2018 |
}
|
|
2019 | 1 |
else if (pd.ident == Id.printf || pd.ident == Id.scanf) |
2020 |
{
|
|
2021 | 1 |
if (pd.args && pd.args.dim != 0) |
2022 |
pd.error("takes no argument"); |
|
2023 | 1 |
goto Ldecl; |
2024 |
}
|
|
2025 | 1 |
else if (global.params.ignoreUnsupportedPragmas) |
2026 |
{
|
|
2027 | 1 |
if (global.params.verbose) |
2028 |
{
|
|
2029 |
/* Print unrecognized pragmas
|
|
2030 |
*/
|
|
2031 | 1 |
OutBuffer buf; |
2032 | 1 |
buf.writestring(pd.ident.toString()); |
2033 | 1 |
if (pd.args) |
2034 |
{
|
|
2035 | 1 |
const errors_save = global.startGagging(); |
2036 | 1 |
for (size_t i = 0; i < pd.args.dim; i++) |
2037 |
{
|
|
2038 | 1 |
Expression e = (*pd.args)[i]; |
2039 | 1 |
sc = sc.startCTFE(); |
2040 | 1 |
e = e.expressionSemantic(sc); |
2041 | 1 |
e = resolveProperties(sc, e); |
2042 | 1 |
sc = sc.endCTFE(); |
2043 | 1 |
e = e.ctfeInterpret(); |
2044 | 1 |
if (i == 0) |
2045 | 1 |
buf.writestring(" ("); |
2046 |
else
|
|
2047 |
buf.writeByte(','); |
|
2048 | 1 |
buf.writestring(e.toChars()); |
2049 |
}
|
|
2050 | 1 |
if (pd.args.dim) |
2051 | 1 |
buf.writeByte(')'); |
2052 | 1 |
global.endGagging(errors_save); |
2053 |
}
|
|
2054 | 1 |
message("pragma %s", buf.peekChars()); |
2055 |
}
|
|
2056 |
}
|
|
2057 |
else
|
|
2058 |
error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars()); |
|
2059 |
Ldecl: |
|
2060 | 1 |
if (pd.decl) |
2061 |
{
|
|
2062 | 1 |
Scope* sc2 = pd.newScope(sc); |
2063 | 1 |
for (size_t i = 0; i < pd.decl.dim; i++) |
2064 |
{
|
|
2065 | 1 |
Dsymbol s = (*pd.decl)[i]; |
2066 | 1 |
s.dsymbolSemantic(sc2); |
2067 | 1 |
if (pd.ident == Id.mangle) |
2068 |
{
|
|
2069 | 1 |
assert(pd.args && pd.args.dim == 1); |
2070 | 1 |
if (auto se = (*pd.args)[0].toStringExp()) |
2071 |
{
|
|
2072 | 1 |
const name = (cast(const(char)[])se.peekData()).xarraydup; |
2073 | 1 |
uint cnt = setMangleOverride(s, name); |
2074 | 1 |
if (cnt > 1) |
2075 | 1 |
pd.error("can only apply to a single declaration"); |
2076 |
}
|
|
2077 |
}
|
|
2078 |
}
|
|
2079 | 1 |
if (sc2 != sc) |
2080 | 1 |
sc2.pop(); |
2081 |
}
|
|
2082 | 1 |
return; |
2083 |
Lnodecl: |
|
2084 | 1 |
if (pd.decl) |
2085 |
{
|
|
2086 | 1 |
pd.error("is missing a terminating `;`"); |
2087 | 1 |
goto Ldecl; |
2088 |
// do them anyway, to avoid segfaults.
|
|
2089 |
}
|
|
2090 |
}
|
|
2091 |
|
|
2092 |
override void visit(StaticIfDeclaration sid) |
|
2093 |
{
|
|
2094 | 1 |
attribSemantic(sid); |
2095 |
}
|
|
2096 |
|
|
2097 |
override void visit(StaticForeachDeclaration sfd) |
|
2098 |
{
|
|
2099 | 1 |
attribSemantic(sfd); |
2100 |
}
|
|
2101 |
|
|
2102 |
private Dsymbols* compileIt(CompileDeclaration cd) |
|
2103 |
{
|
|
2104 |
//printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars());
|
|
2105 | 1 |
OutBuffer buf; |
2106 | 1 |
if (expressionsToString(buf, sc, cd.exps)) |
2107 | 1 |
return null; |
2108 |
|
|
2109 | 1 |
const errors = global.errors; |
2110 | 1 |
const len = buf.length; |
2111 | 1 |
buf.writeByte(0); |
2112 | 1 |
const str = buf.extractSlice()[0 .. len]; |
2113 | 1 |
scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false); |
2114 | 1 |
p.nextToken(); |
2115 |
|
|
2116 | 1 |
auto d = p.parseDeclDefs(0); |
2117 | 1 |
if (global.errors != errors) |
2118 | 1 |
return null; |
2119 |
|
|
2120 | 1 |
if (p.token.value != TOK.endOfFile) |
2121 |
{
|
|
2122 |
cd.error("incomplete mixin declaration `%s`", str.ptr); |
|
2123 |
return null; |
|
2124 |
}
|
|
2125 | 1 |
return d; |
2126 |
}
|
|
2127 |
|
|
2128 |
/***********************************************************
|
|
2129 |
* https://dlang.org/spec/module.html#mixin-declaration
|
|
2130 |
*/
|
|
2131 |
override void visit(CompileDeclaration cd) |
|
2132 |
{
|
|
2133 |
//printf("CompileDeclaration::semantic()\n");
|
|
2134 | 1 |
if (!cd.compiled) |
2135 |
{
|
|
2136 | 1 |
cd.decl = compileIt(cd); |
2137 | 1 |
cd.AttribDeclaration.addMember(sc, cd.scopesym); |
2138 | 1 |
cd.compiled = true; |
2139 |
|
|
2140 | 1 |
if (cd._scope && cd.decl) |
2141 |
{
|
|
2142 | 1 |
for (size_t i = 0; i < cd.decl.dim; i++) |
2143 |
{
|
|
2144 | 1 |
Dsymbol s = (*cd.decl)[i]; |
2145 | 1 |
s.setScope(cd._scope); |
2146 |
}
|
|
2147 |
}
|
|
2148 |
}
|
|
2149 | 1 |
attribSemantic(cd); |
2150 |
}
|
|
2151 |
|
|
2152 |
override void visit(CPPNamespaceDeclaration ns) |
|
2153 |
{
|
|
2154 |
Identifier identFromSE (StringExp se) |
|
2155 |
{
|
|
2156 | 1 |
const sident = se.toStringz(); |
2157 | 1 |
if (!sident.length || !Identifier.isValidIdentifier(sident)) |
2158 |
{
|
|
2159 | 1 |
ns.exp.error("expected valid identifer for C++ namespace but got `%.*s`", |
2160 |
cast(int)sident.length, sident.ptr); |
|
2161 | 1 |
return null; |
2162 |
}
|
|
2163 |
else
|
|
2164 | 1 |
return Identifier.idPool(sident); |
2165 |
}
|
|
2166 |
|
|
2167 | 1 |
if (ns.ident is null) |
2168 |
{
|
|
2169 | 1 |
ns.cppnamespace = sc.namespace; |
2170 | 1 |
sc = sc.startCTFE(); |
2171 | 1 |
ns.exp = ns.exp.expressionSemantic(sc); |
2172 | 1 |
ns.exp = resolveProperties(sc, ns.exp); |
2173 | 1 |
sc = sc.endCTFE(); |
2174 | 1 |
ns.exp = ns.exp.ctfeInterpret(); |
2175 |
// Can be either a tuple of strings or a string itself
|
|
2176 | 1 |
if (auto te = ns.exp.isTupleExp()) |
2177 |
{
|
|
2178 | 1 |
expandTuples(te.exps); |
2179 | 1 |
CPPNamespaceDeclaration current = ns.cppnamespace; |
2180 | 1 |
for (size_t d = 0; d < te.exps.dim; ++d) |
2181 |
{
|
|
2182 | 1 |
auto exp = (*te.exps)[d]; |
2183 | 1 |
auto prev = d ? current : ns.cppnamespace; |
2184 | 1 |
current = (d + 1) != te.exps.dim |
2185 | 1 |
? new CPPNamespaceDeclaration(exp, null) |
2186 | 1 |
: ns; |
2187 | 1 |
current.exp = exp; |
2188 | 1 |
current.cppnamespace = prev; |
2189 | 1 |
if (auto se = exp.toStringExp()) |
2190 |
{
|
|
2191 | 1 |
current.ident = identFromSE(se); |
2192 | 1 |
if (current.ident is null) |
2193 |
return; // An error happened in `identFromSE` |
|
2194 |
}
|
|
2195 |
else
|
|
2196 |
ns.exp.error("`%s`: index %llu is not a string constant, it is a `%s`", |
|
2197 |
ns.exp.toChars(), cast(ulong) d, ns.exp.type.toChars()); |
|
2198 |
}
|
|
2199 |
}
|
|
2200 | 1 |
else if (auto se = ns.exp.toStringExp()) |
2201 | 1 |
ns.ident = identFromSE(se); |
2202 |
else
|
|
2203 | 1 |
ns.exp.error("compile time string constant (or tuple) expected, not `%s`", |
2204 |
ns.exp.toChars()); |
|
2205 |
}
|
|
2206 | 1 |
if (ns.ident) |
2207 | 1 |
attribSemantic(ns); |
2208 |
}
|
|
2209 |
|
|
2210 |
override void visit(UserAttributeDeclaration uad) |
|
2211 |
{
|
|
2212 |
//printf("UserAttributeDeclaration::semantic() %p\n", this);
|
|
2213 | 1 |
if (uad.decl && !uad._scope) |
2214 | 1 |
uad.Dsymbol.setScope(sc); // for function local symbols |
2215 | 1 |
arrayExpressionSemantic(uad.atts, sc, true); |
2216 | 1 |
return attribSemantic(uad); |
2217 |
}
|
|
2218 |
|
|
2219 |
override void visit(StaticAssert sa) |
|
2220 |
{
|
|
2221 | 1 |
if (sa.semanticRun < PASS.semanticdone) |
2222 | 1 |
sa.semanticRun = PASS.semanticdone; |
2223 |
}
|
|
2224 |
|
|
2225 |
override void visit(DebugSymbol ds) |
|
2226 |
{
|
|
2227 |
//printf("DebugSymbol::semantic() %s\n", toChars());
|
|
2228 | 1 |
if (ds.semanticRun < PASS.semanticdone) |
2229 | 1 |
ds.semanticRun = PASS.semanticdone; |
2230 |
}
|
|
2231 |
|
|
2232 |
override void visit(VersionSymbol vs) |
|
2233 |
{
|
|
2234 | 1 |
if (vs.semanticRun < PASS.semanticdone) |
2235 | 1 |
vs.semanticRun = PASS.semanticdone; |
2236 |
}
|
|
2237 |
|
|
2238 |
override void visit(Package pkg) |
|
2239 |
{
|
|
2240 | 1 |
if (pkg.semanticRun < PASS.semanticdone) |
2241 | 1 |
pkg.semanticRun = PASS.semanticdone; |
2242 |
}
|
|
2243 |
|
|
2244 |
override void visit(Module m) |
|
2245 |
{
|
|
2246 | 1 |
if (m.semanticRun != PASS.init) |
2247 | 1 |
return; |
2248 |
//printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
|
|
2249 | 1 |
m.semanticRun = PASS.semantic; |
2250 |
// Note that modules get their own scope, from scratch.
|
|
2251 |
// This is so regardless of where in the syntax a module
|
|
2252 |
// gets imported, it is unaffected by context.
|
|
2253 | 1 |
Scope* sc = m._scope; // see if already got one from importAll() |
2254 | 1 |
if (!sc) |
2255 |
{
|
|
2256 |
Scope.createGlobal(m); // create root scope |
|
2257 |
}
|
|
2258 |
|
|
2259 |
//printf("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage);
|
|
2260 |
// Pass 1 semantic routines: do public side of the definition
|
|
2261 | 1 |
m.members.foreachDsymbol( (s) |
2262 |
{
|
|
2263 |
//printf("\tModule('%s'): '%s'.dsymbolSemantic()\n", toChars(), s.toChars());
|
|
2264 | 1 |
s.dsymbolSemantic(sc); |
2265 | 1 |
m.runDeferredSemantic(); |
2266 |
});
|
|
2267 |
|
|
2268 | 1 |
if (m.userAttribDecl) |
2269 |
{
|
|
2270 | 1 |
m.userAttribDecl.dsymbolSemantic(sc); |
2271 |
}
|
|
2272 | 1 |
if (!m._scope) |
2273 |
{
|
|
2274 |
sc = sc.pop(); |
|
2275 |
sc.pop(); // 2 pops because Scope::createGlobal() created 2 |
|
2276 |
}
|
|
2277 | 1 |
m.semanticRun = PASS.semanticdone; |
2278 |
//printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
|
|
2279 |
}
|
|
2280 |
|
|
2281 |
override void visit(EnumDeclaration ed) |
|
2282 |
{
|
|
2283 |
//printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), toChars());
|
|
2284 |
//printf("EnumDeclaration::semantic() %p %s\n", this, toChars());
|
|
2285 | 1 |
if (ed.semanticRun >= PASS.semanticdone) |
2286 | 1 |
return; // semantic() already completed |
2287 | 1 |
if (ed.semanticRun == PASS.semantic) |
2288 |
{
|
|
2289 | 1 |
assert(ed.memtype); |
2290 | 1 |
error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); |
2291 | 1 |
ed.errors = true; |
2292 | 1 |
ed.semanticRun = PASS.semanticdone; |
2293 | 1 |
return; |
2294 |
}
|
|
2295 | 1 |
uint dprogress_save = Module.dprogress; |
2296 |
|
|
2297 | 1 |
Scope* scx = null; |
2298 | 1 |
if (ed._scope) |
2299 |
{
|
|
2300 | 1 |
sc = ed._scope; |
2301 | 1 |
scx = ed._scope; // save so we don't make redundant copies |
2302 | 1 |
ed._scope = null; |
2303 |
}
|
|
2304 |
|
|
2305 | 1 |
if (!sc) |
2306 |
return; |
|
2307 |
|
|
2308 | 1 |
ed.parent = sc.parent; |
2309 | 1 |
ed.type = ed.type.typeSemantic(ed.loc, sc); |
2310 |
|
|
2311 | 1 |
ed.protection = sc.protection; |
2312 | 1 |
if (sc.stc & STC.deprecated_) |
2313 | 1 |
ed.isdeprecated = true; |
2314 | 1 |
ed.userAttribDecl = sc.userAttribDecl; |
2315 | 1 |
ed.cppnamespace = sc.namespace; |
2316 |
|
|
2317 | 1 |
ed.semanticRun = PASS.semantic; |
2318 | 1 |
UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); |
2319 |
|
|
2320 | 1 |
if (!ed.members && !ed.memtype) // enum ident; |
2321 |
{
|
|
2322 | 1 |
ed.semanticRun = PASS.semanticdone; |
2323 | 1 |
return; |
2324 |
}
|
|
2325 |
|
|
2326 | 1 |
if (!ed.symtab) |
2327 | 1 |
ed.symtab = new DsymbolTable(); |
2328 |
|
|
2329 |
/* The separate, and distinct, cases are:
|
|
2330 |
* 1. enum { ... }
|
|
2331 |
* 2. enum : memtype { ... }
|
|
2332 |
* 3. enum ident { ... }
|
|
2333 |
* 4. enum ident : memtype { ... }
|
|
2334 |
* 5. enum ident : memtype;
|
|
2335 |
* 6. enum ident;
|
|
2336 |
*/
|
|
2337 |
|
|
2338 | 1 |
if (ed.memtype) |
2339 |
{
|
|
2340 | 1 |
ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); |
2341 |
|
|
2342 |
/* Check to see if memtype is forward referenced
|
|
2343 |
*/
|
|
2344 | 1 |
if (auto te = ed.memtype.isTypeEnum()) |
2345 |
{
|
|
2346 | 1 |
EnumDeclaration sym = cast(EnumDeclaration)te.toDsymbol(sc); |
2347 | 1 |
if (!sym.memtype || !sym.members || !sym.symtab || sym._scope) |
2348 |
{
|
|
2349 |
// memtype is forward referenced, so try again later
|
|
2350 | 1 |
deferDsymbolSemantic(ed, scx); |
2351 | 1 |
Module.dprogress = dprogress_save; |
2352 |
//printf("\tdeferring %s\n", toChars());
|
|
2353 | 1 |
ed.semanticRun = PASS.init; |
2354 | 1 |
return; |
2355 |
}
|
|
2356 |
}
|
|
2357 | 1 |
if (ed.memtype.ty == Tvoid) |
2358 |
{
|
|
2359 | 1 |
ed.error("base type must not be `void`"); |
2360 | 1 |
ed.memtype = Type.terror; |
2361 |
}
|
|
2362 | 1 |
if (ed.memtype.ty == Terror) |
2363 |
{
|
|
2364 | 1 |
ed.errors = true; |
2365 |
// poison all the members
|
|
2366 | 1 |
ed.members.foreachDsymbol( (s) { s.errors = true; } ); |
2367 | 1 |
ed.semanticRun = PASS.semanticdone; |
2368 | 1 |
return; |
2369 |
}
|
|
2370 |
}
|
|
2371 |
|
|
2372 | 1 |
ed.semanticRun = PASS.semanticdone; |
2373 |
|
|
2374 | 1 |
if (!ed.members) // enum ident : memtype; |
2375 | 1 |
return; |
2376 |
|
|
2377 | 1 |
if (ed.members.dim == 0) |
2378 |
{
|
|
2379 |
ed.error("enum `%s` must have at least one member", ed.toChars()); |
|
2380 |
ed.errors = true; |
|
2381 |
return; |
|
2382 |
}
|
|
2383 |
|
|
2384 | 1 |
Module.dprogress++; |
2385 |
|
|
2386 | 1 |
Scope* sce; |
2387 | 1 |
if (ed.isAnonymous()) |
2388 | 1 |
sce = sc; |
2389 |
else
|
|
2390 |
{
|
|
2391 | 1 |
sce = sc.push(ed); |
2392 | 1 |
sce.parent = ed; |
2393 |
}
|
|
2394 | 1 |
sce = sce.startCTFE(); |
2395 | 1 |
sce.setNoFree(); // needed for getMaxMinValue() |
2396 |
|
|
2397 |
/* Each enum member gets the sce scope
|
|
2398 |
*/
|
|
2399 | 1 |
ed.members.foreachDsymbol( (s) |
2400 |
{
|
|
2401 | 1 |
EnumMember em = s.isEnumMember(); |
2402 | 1 |
if (em) |
2403 | 1 |
em._scope = sce; |
2404 |
});
|
|
2405 |
|
|
2406 | 1 |
if (!ed.added) |
2407 |
{
|
|
2408 |
/* addMember() is not called when the EnumDeclaration appears as a function statement,
|
|
2409 |
* so we have to do what addMember() does and install the enum members in the right symbol
|
|
2410 |
* table
|
|
2411 |
*/
|
|
2412 | 1 |
ScopeDsymbol scopesym = null; |
2413 | 1 |
if (ed.isAnonymous()) |
2414 |
{
|
|
2415 |
/* Anonymous enum members get added to enclosing scope.
|
|
2416 |
*/
|
|
2417 | 1 |
for (Scope* sct = sce; 1; sct = sct.enclosing) |
2418 |
{
|
|
2419 | 1 |
assert(sct); |
2420 | 1 |
if (sct.scopesym) |
2421 |
{
|
|
2422 | 1 |
scopesym = sct.scopesym; |
2423 | 1 |
if (!sct.scopesym.symtab) |
2424 | 1 |
sct.scopesym.symtab = new DsymbolTable(); |
2425 | 1 |
break; |
2426 |
}
|
|
2427 |
}
|
|
2428 |
}
|
|
2429 |
else
|
|
2430 |
{
|
|
2431 |
// Otherwise enum members are in the EnumDeclaration's symbol table
|
|
2432 | 1 |
scopesym = ed; |
2433 |
}
|
|
2434 |
|
|
2435 | 1 |
ed.members.foreachDsymbol( (s) |
2436 |
{
|
|
2437 | 1 |
EnumMember em = s.isEnumMember(); |
2438 | 1 |
if (em) |
2439 |
{
|
|
2440 | 1 |
em.ed = ed; |
2441 | 1 |
em.addMember(sc, scopesym); |
2442 |
}
|
|
2443 |
});
|
|
2444 |
}
|
|
2445 |
|
|
2446 | 1 |
ed.members.foreachDsymbol( (s) |
2447 |
{
|
|
2448 | 1 |
EnumMember em = s.isEnumMember(); |
2449 | 1 |
if (em) |
2450 | 1 |
em.dsymbolSemantic(em._scope); |
2451 |
});
|
|
2452 |
//printf("defaultval = %lld\n", defaultval);
|
|
2453 |
|
|
2454 |
//if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars());
|
|
2455 |
//printf("members = %s\n", members.toChars());
|
|
2456 |
}
|
|
2457 |
|
|
2458 |
override void visit(EnumMember em) |
|
2459 |
{
|
|
2460 |
//printf("EnumMember::semantic() %s\n", toChars());
|
|
2461 |
|
|
2462 |
void errorReturn() |
|
2463 |
{
|
|
2464 | 1 |
em.errors = true; |
2465 | 1 |
em.semanticRun = PASS.semanticdone; |
2466 |
}
|
|
2467 |
|
|
2468 | 1 |
if (em.errors || em.semanticRun >= PASS.semanticdone) |
2469 | 1 |
return; |
2470 | 1 |
if (em.semanticRun == PASS.semantic) |
2471 |
{
|
|
2472 | 1 |
em.error("circular reference to `enum` member"); |
2473 | 1 |
return errorReturn(); |
2474 |
}
|
|
2475 | 1 |
assert(em.ed); |
2476 |
|
|
2477 | 1 |
em.ed.dsymbolSemantic(sc); |
2478 | 1 |
if (em.ed.errors) |
2479 | 1 |
return errorReturn(); |
2480 | 1 |
if (em.errors || em.semanticRun >= PASS.semanticdone) |
2481 | 1 |
return; |
2482 |
|
|
2483 | 1 |
if (em._scope) |
2484 | 1 |
sc = em._scope; |
2485 | 1 |
if (!sc) |
2486 |
return; |
|
2487 |
|
|
2488 | 1 |
em.semanticRun = PASS.semantic; |
2489 |
|
|
2490 | 1 |
em.protection = em.ed.isAnonymous() ? em.ed.protection : Prot(Prot.Kind.public_); |
2491 | 1 |
em.linkage = LINK.d; |
2492 | 1 |
em.storage_class |= STC.manifest; |
2493 |
|
|
2494 |
// https://issues.dlang.org/show_bug.cgi?id=9701
|
|
2495 | 1 |
if (em.ed.isAnonymous()) |
2496 |
{
|
|
2497 | 1 |
if (em.userAttribDecl) |
2498 | 1 |
em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; |
2499 |
else
|
|
2500 | 1 |
em.userAttribDecl = em.ed.userAttribDecl; |
2501 |
}
|
|
2502 |
|
|
2503 |
// Eval UDA in this same scope. Issues 19344, 20835, 21122
|
|
2504 | 1 |
if (em.userAttribDecl) |
2505 | 1 |
em.userAttribDecl.setScope(sc); |
2506 |
|
|
2507 |
// The first enum member is special
|
|
2508 | 1 |
bool first = (em == (*em.ed.members)[0]); |
2509 |
|
|
2510 | 1 |
if (em.origType) |
2511 |
{
|
|
2512 | 1 |
em.origType = em.origType.typeSemantic(em.loc, sc); |
2513 | 1 |
em.type = em.origType; |
2514 | 1 |
assert(em.value); // "type id;" is not a valid enum member declaration |
2515 |
}
|
|
2516 |
|
|
2517 | 1 |
if (em.value) |
2518 |
{
|
|
2519 | 1 |
Expression e = em.value; |
2520 | 1 |
assert(e.dyncast() == DYNCAST.expression); |
2521 | 1 |
e = e.expressionSemantic(sc); |
2522 | 1 |
e = resolveProperties(sc, e); |
2523 | 1 |
e = e.ctfeInterpret(); |
2524 | 1 |
if (e.op == TOK.error) |
2525 | 1 |
return errorReturn(); |
2526 | 1 |
if (first && !em.ed.memtype && !em.ed.isAnonymous()) |
2527 |
{
|
|
2528 | 1 |
em.ed.memtype = e.type; |
2529 | 1 |
if (em.ed.memtype.ty == Terror) |
2530 |
{
|
|
2531 |
em.ed.errors = true; |
|
2532 |
return errorReturn(); |
|
2533 |
}
|
|
2534 | 1 |
if (em.ed.memtype.ty != Terror) |
2535 |
{
|
|
2536 |
/* https://issues.dlang.org/show_bug.cgi?id=11746
|
|
2537 |
* All of named enum members should have same type
|
|
2538 |
* with the first member. If the following members were referenced
|
|
2539 |
* during the first member semantic, their types should be unified.
|
|
2540 |
*/
|
|
2541 | 1 |
em.ed.members.foreachDsymbol( (s) |
2542 |
{
|
|
2543 | 1 |
EnumMember enm = s.isEnumMember(); |
2544 | 1 |
if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) |
2545 | 1 |
return; |
2546 |
|
|
2547 |
//printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun);
|
|
2548 | 1 |
Expression ev = enm.value; |
2549 | 1 |
ev = ev.implicitCastTo(sc, em.ed.memtype); |
2550 | 1 |
ev = ev.ctfeInterpret(); |
2551 | 1 |
ev = ev.castTo(sc, em.ed.type); |
2552 | 1 |
if (ev.op == TOK.error) |
2553 | 1 |
em.ed.errors = true; |
2554 | 1 |
enm.value = ev; |
2555 |
});
|
|
2556 |
|
|
2557 | 1 |
if (em.ed.errors) |
2558 |
{
|
|
2559 | 1 |
em.ed.memtype = Type.terror; |
2560 | 1 |
return errorReturn(); |
2561 |
}
|
|
2562 |
}
|
|
2563 |
}
|
|
2564 |
|
|
2565 | 1 |
if (em.ed.memtype && !em.origType) |
2566 |
{
|
|
2567 | 1 |
e = e.implicitCastTo(sc, em.ed.memtype); |
2568 | 1 |
e = e.ctfeInterpret(); |
2569 |
|
|
2570 |
// save origValue for better json output
|
|
2571 | 1 |
em.origValue = e; |
2572 |
|
|
2573 | 1 |
if (!em.ed.isAnonymous()) |
2574 |
{
|
|
2575 | 1 |
e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 |
2576 | 1 |
e = e.ctfeInterpret(); |
2577 |
}
|
|
2578 |
}
|
|
2579 | 1 |
else if (em.origType) |
2580 |
{
|
|
2581 | 1 |
e = e.implicitCastTo(sc, em.origType); |
2582 | 1 |
e = e.ctfeInterpret(); |
2583 | 1 |
assert(em.ed.isAnonymous()); |
2584 |
|
|
2585 |
// save origValue for better json output
|
|
2586 | 1 |
em.origValue = e; |
2587 |
}
|
|
2588 | 1 |
em.value = e; |
2589 |
}
|
|
2590 | 1 |
else if (first) |
2591 |
{
|
|
2592 | 1 |
Type t; |
2593 | 1 |
if (em.ed.memtype) |
2594 | 1 |
t = em.ed.memtype; |
2595 |
else
|
|
2596 |
{
|
|
2597 | 1 |
t = Type.tint32; |
2598 | 1 |
if (!em.ed.isAnonymous()) |
2599 | 1 |
em.ed.memtype = t; |
2600 |
}
|
|
2601 | 1 |
Expression e = new IntegerExp(em.loc, 0, t); |
2602 | 1 |
e = e.ctfeInterpret(); |
2603 |
|
|
2604 |
// save origValue for better json output
|
|
2605 | 1 |
em.origValue = e; |
2606 |
|
|
2607 | 1 |
if (!em.ed.isAnonymous()) |
2608 |
{
|
|
2609 | 1 |
e = e.castTo(sc, em.ed.type); |
2610 | 1 |
e = e.ctfeInterpret(); |
2611 |
}
|
|
2612 | 1 |
em.value = e; |
2613 |
}
|
|
2614 |
else
|
|
2615 |
{
|
|
2616 |
/* Find the previous enum member,
|
|
2617 |
* and set this to be the previous value + 1
|
|
2618 |
*/
|
|
2619 | 1 |
EnumMember emprev = null; |
2620 | 1 |
em.ed.members.foreachDsymbol( (s) |
2621 |
{
|
|
2622 | 1 |
if (auto enm = s.isEnumMember()) |
2623 |
{
|
|
2624 | 1 |
if (enm == em) |
2625 | 1 |
return 1; // found |
2626 | 1 |
emprev = enm; |
2627 |
}
|
|
2628 | 1 |
return 0; // continue |
2629 |
});
|
|
2630 |
|
|
2631 | 1 |
assert(emprev); |
2632 | 1 |
if (emprev.semanticRun < PASS.semanticdone) // if forward reference |
2633 | 1 |
emprev.dsymbolSemantic(emprev._scope); // resolve it |
2634 | 1 |
if (emprev.errors) |
2635 | 1 |
return errorReturn(); |
2636 |
|
|
2637 | 1 |
Expression eprev = emprev.value; |
2638 |
// .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645
|
|
2639 | 1 |
Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) |
2640 | 1 |
? em.ed.memtype |
2641 | 1 |
: eprev.type; |
2642 |
|
|
2643 | 1 |
Expression emax = tprev.getProperty(sc, em.ed.loc, Id.max, 0); |
2644 | 1 |
emax = emax.expressionSemantic(sc); |
2645 | 1 |
emax = emax.ctfeInterpret(); |
2646 |
|
|
2647 |
// Set value to (eprev + 1).
|
|
2648 |
// But first check that (eprev != emax)
|
|
2649 | 1 |
assert(eprev); |
2650 | 1 |
Expression e = new EqualExp(TOK.equal, em.loc, eprev, emax); |
2651 | 1 |
e = e.expressionSemantic(sc); |
2652 | 1 |
e = e.ctfeInterpret(); |
2653 | 1 |
if (e.toInteger()) |
2654 |
{
|
|
2655 | 1 |
em.error("initialization with `%s.%s+1` causes overflow for type `%s`", |
2656 |
emprev.ed.toChars(), emprev.toChars(), em.ed.memtype.toChars()); |
|
2657 | 1 |
return errorReturn(); |
2658 |
}
|
|
2659 |
|
|
2660 |
// Now set e to (eprev + 1)
|
|
2661 | 1 |
e = new AddExp(em.loc, eprev, IntegerExp.literal!1); |
2662 | 1 |
e = e.expressionSemantic(sc); |
2663 | 1 |
e = e.castTo(sc, eprev.type); |
2664 | 1 |
e = e.ctfeInterpret(); |
2665 |
|
|
2666 |
// save origValue (without cast) for better json output
|
|
2667 | 1 |
if (e.op != TOK.error) // avoid duplicate diagnostics |
2668 |
{
|
|
2669 | 1 |
assert(emprev.origValue); |
2670 | 1 |
em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); |
2671 | 1 |
em.origValue = em.origValue.expressionSemantic(sc); |
2672 | 1 |
em.origValue = em.origValue.ctfeInterpret(); |
2673 |
}
|
|
2674 |
|
|
2675 | 1 |
if (e.op == TOK.error) |
2676 | 1 |
return errorReturn(); |
2677 | 1 |
if (e.type.isfloating()) |
2678 |
{
|
|
2679 |
// Check that e != eprev (not always true for floats)
|
|
2680 | 1 |
Expression etest = new EqualExp(TOK.equal, em.loc, e, eprev); |
2681 | 1 |
etest = etest.expressionSemantic(sc); |
2682 | 1 |
etest = etest.ctfeInterpret(); |
2683 | 1 |
if (etest.toInteger()) |
2684 |
{
|
|
2685 | 1 |
em.error("has inexact value due to loss of precision"); |
2686 | 1 |
return errorReturn(); |
2687 |
}
|
|
2688 |
}
|
|
2689 | 1 |
em.value = e; |
2690 |
}
|
|
2691 | 1 |
if (!em.origType) |
2692 | 1 |
em.type = em.value.type; |
2693 |
|
|
2694 | 1 |
assert(em.origValue); |
2695 | 1 |
em.semanticRun = PASS.semanticdone; |
2696 |
}
|
|
2697 |
|
|
2698 |
override void visit(TemplateDeclaration tempdecl) |
|
2699 |
{
|
|
2700 |
static if (LOG) |
|
2701 |
{
|
|
2702 |
printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars()); |
|
2703 |
printf("sc.stc = %llx\n", sc.stc); |
|
2704 |
printf("sc.module = %s\n", sc._module.toChars()); |
|
2705 |
}
|
|
2706 | 1 |
if (tempdecl.semanticRun != PASS.init) |
2707 | 1 |
return; // semantic() already run |
2708 |
|
|
2709 | 1 |
if (tempdecl._scope) |
2710 |
{
|
|
2711 | 1 |
sc = tempdecl._scope; |
2712 | 1 |
tempdecl._scope = null; |
2713 |
}
|
|
2714 | 1 |
if (!sc) |
2715 |
return; |
|
2716 |
|
|
2717 |
// Remember templates defined in module object that we need to know about
|
|
2718 | 1 |
if (sc._module && sc._module.ident == Id.object) |
2719 |
{
|
|
2720 | 1 |
if (tempdecl |