]>
Commit | Line | Data |
---|---|---|
5fee5ec3 IB |
1 | /** |
2 | * Does the semantic 1 pass on the AST, which looks at symbol declarations but not initializers | |
3 | * or function bodies. | |
4 | * | |
c43b5909 IB |
5 | * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved |
6 | * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) | |
7 | * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | |
5fee5ec3 IB |
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.apply; | |
21 | import dmd.arraytypes; | |
22 | import dmd.astcodegen; | |
23 | import dmd.astenums; | |
24 | import dmd.attrib; | |
25 | import dmd.blockexit; | |
26 | import dmd.clone; | |
27 | import dmd.compiler; | |
28 | import dmd.dcast; | |
29 | import dmd.dclass; | |
30 | import dmd.declaration; | |
31 | import dmd.denum; | |
32 | import dmd.dimport; | |
33 | import dmd.dinterpret; | |
34 | import dmd.dmangle; | |
35 | import dmd.dmodule; | |
36 | import dmd.dscope; | |
37 | import dmd.dstruct; | |
38 | import dmd.dsymbol; | |
39 | import dmd.dtemplate; | |
40 | import dmd.dversion; | |
41 | import dmd.errors; | |
42 | import dmd.escape; | |
43 | import dmd.expression; | |
44 | import dmd.expressionsem; | |
45 | import dmd.func; | |
46 | import dmd.globals; | |
47 | import dmd.id; | |
48 | import dmd.identifier; | |
fd43568c | 49 | import dmd.importc; |
5fee5ec3 IB |
50 | import dmd.init; |
51 | import dmd.initsem; | |
445d8def | 52 | import dmd.intrange; |
5fee5ec3 IB |
53 | import dmd.hdrgen; |
54 | import dmd.mtype; | |
31350635 | 55 | import dmd.mustuse; |
5fee5ec3 IB |
56 | import dmd.nogc; |
57 | import dmd.nspace; | |
58 | import dmd.objc; | |
59 | import dmd.opover; | |
60 | import dmd.parse; | |
c8dfa79c | 61 | import dmd.root.array; |
5fee5ec3 | 62 | import dmd.root.filename; |
0fb57034 | 63 | import dmd.common.outbuffer; |
5fee5ec3 IB |
64 | import dmd.root.rmem; |
65 | import dmd.root.rootobject; | |
c43b5909 | 66 | import dmd.root.utf; |
5fee5ec3 IB |
67 | import dmd.semantic2; |
68 | import dmd.semantic3; | |
69 | import dmd.sideeffect; | |
70 | import dmd.statementsem; | |
71 | import dmd.staticassert; | |
72 | import dmd.tokens; | |
5fee5ec3 IB |
73 | import dmd.utils; |
74 | import dmd.statement; | |
75 | import dmd.target; | |
76 | import dmd.templateparamsem; | |
77 | import dmd.typesem; | |
78 | import dmd.visitor; | |
79 | ||
80 | enum LOG = false; | |
81 | ||
82 | private uint setMangleOverride(Dsymbol s, const(char)[] sym) | |
83 | { | |
84 | if (s.isFuncDeclaration() || s.isVarDeclaration()) | |
85 | { | |
86 | s.isDeclaration().mangleOverride = sym; | |
87 | return 1; | |
88 | } | |
89 | ||
90 | if (auto ad = s.isAttribDeclaration()) | |
91 | { | |
92 | uint nestedCount = 0; | |
93 | ||
94 | ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } ); | |
95 | ||
96 | return nestedCount; | |
97 | } | |
98 | return 0; | |
99 | } | |
100 | ||
101 | /************************************* | |
102 | * Does semantic analysis on the public face of declarations. | |
103 | */ | |
104 | extern(C++) void dsymbolSemantic(Dsymbol dsym, Scope* sc) | |
105 | { | |
106 | scope v = new DsymbolSemanticVisitor(sc); | |
107 | dsym.accept(v); | |
108 | } | |
109 | ||
110 | /*************************************************** | |
111 | * Determine the numerical value of the AlignmentDeclaration | |
112 | * Params: | |
113 | * ad = AlignmentDeclaration | |
114 | * sc = context | |
115 | * Returns: | |
0fb57034 | 116 | * ad with alignment value determined |
5fee5ec3 | 117 | */ |
0fb57034 | 118 | AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc) |
5fee5ec3 | 119 | { |
0fb57034 IB |
120 | if (!ad.salign.isUnknown()) // UNKNOWN is 0 |
121 | return ad; | |
5fee5ec3 IB |
122 | |
123 | if (!ad.exps) | |
0fb57034 IB |
124 | { |
125 | ad.salign.setDefault(); | |
126 | return ad; | |
127 | } | |
5fee5ec3 IB |
128 | |
129 | dinteger_t strictest = 0; // strictest alignment | |
130 | bool errors; | |
131 | foreach (ref exp; (*ad.exps)[]) | |
132 | { | |
133 | sc = sc.startCTFE(); | |
134 | auto e = exp.expressionSemantic(sc); | |
135 | e = resolveProperties(sc, e); | |
136 | sc = sc.endCTFE(); | |
137 | e = e.ctfeInterpret(); | |
138 | exp = e; // could be re-evaluated if exps are assigned to more than one AlignDeclaration by CParser.applySpecifier(), | |
139 | // e.g. `_Alignas(8) int a, b;` | |
9c7d5e88 | 140 | if (e.op == EXP.error) |
5fee5ec3 IB |
141 | errors = true; |
142 | else | |
143 | { | |
144 | auto n = e.toInteger(); | |
145 | if (sc.flags & SCOPE.Cfile && n == 0) // C11 6.7.5-6 allows 0 for alignment | |
146 | continue; | |
147 | ||
0fb57034 | 148 | if (n < 1 || n & (n - 1) || ushort.max < n || !e.type.isintegral()) |
5fee5ec3 IB |
149 | { |
150 | error(ad.loc, "alignment must be an integer positive power of 2, not 0x%llx", cast(ulong)n); | |
151 | errors = true; | |
152 | } | |
153 | if (n > strictest) // C11 6.7.5-6 | |
154 | strictest = n; | |
155 | } | |
156 | } | |
157 | ||
0fb57034 IB |
158 | if (errors || strictest == 0) // C11 6.7.5-6 says alignment of 0 means no effect |
159 | ad.salign.setDefault(); | |
160 | else | |
161 | ad.salign.set(cast(uint) strictest); | |
162 | ||
163 | return ad; | |
5fee5ec3 IB |
164 | } |
165 | ||
166 | const(char)* getMessage(DeprecatedDeclaration dd) | |
167 | { | |
168 | if (auto sc = dd._scope) | |
169 | { | |
170 | dd._scope = null; | |
171 | ||
172 | sc = sc.startCTFE(); | |
173 | dd.msg = dd.msg.expressionSemantic(sc); | |
174 | dd.msg = resolveProperties(sc, dd.msg); | |
175 | sc = sc.endCTFE(); | |
176 | dd.msg = dd.msg.ctfeInterpret(); | |
177 | ||
178 | if (auto se = dd.msg.toStringExp()) | |
179 | dd.msgstr = se.toStringz().ptr; | |
180 | else | |
181 | dd.msg.error("compile time constant expected, not `%s`", dd.msg.toChars()); | |
182 | } | |
183 | return dd.msgstr; | |
184 | } | |
185 | ||
186 | ||
187 | // Returns true if a contract can appear without a function body. | |
188 | package bool allowsContractWithoutBody(FuncDeclaration funcdecl) | |
189 | { | |
190 | assert(!funcdecl.fbody); | |
191 | ||
192 | /* Contracts can only appear without a body when they are virtual | |
193 | * interface functions or abstract. | |
194 | */ | |
195 | Dsymbol parent = funcdecl.toParent(); | |
196 | InterfaceDeclaration id = parent.isInterfaceDeclaration(); | |
197 | ||
198 | if (!funcdecl.isAbstract() && | |
199 | (funcdecl.fensures || funcdecl.frequires) && | |
200 | !(id && funcdecl.isVirtual())) | |
201 | { | |
202 | auto cd = parent.isClassDeclaration(); | |
203 | if (!(cd && cd.isAbstract())) | |
204 | return false; | |
205 | } | |
206 | return true; | |
207 | } | |
208 | ||
209 | private extern(C++) final class DsymbolSemanticVisitor : Visitor | |
210 | { | |
211 | alias visit = Visitor.visit; | |
212 | ||
213 | Scope* sc; | |
214 | this(Scope* sc) | |
215 | { | |
216 | this.sc = sc; | |
217 | } | |
218 | ||
219 | // Save the scope and defer semantic analysis on the Dsymbol. | |
220 | private void deferDsymbolSemantic(Dsymbol s, Scope *scx) | |
221 | { | |
222 | s._scope = scx ? scx : sc.copy(); | |
223 | s._scope.setNoFree(); | |
224 | Module.addDeferredSemantic(s); | |
225 | } | |
226 | ||
227 | override void visit(Dsymbol dsym) | |
228 | { | |
229 | dsym.error("%p has no semantic routine", dsym); | |
230 | } | |
231 | ||
232 | override void visit(ScopeDsymbol) { } | |
233 | override void visit(Declaration) { } | |
234 | ||
235 | override void visit(AliasThis dsym) | |
236 | { | |
235d5a96 | 237 | if (dsym.semanticRun != PASS.initial) |
5fee5ec3 IB |
238 | return; |
239 | ||
240 | if (dsym._scope) | |
241 | { | |
242 | sc = dsym._scope; | |
243 | dsym._scope = null; | |
244 | } | |
245 | ||
246 | if (!sc) | |
247 | return; | |
248 | ||
249 | dsym.semanticRun = PASS.semantic; | |
250 | dsym.isDeprecated_ = !!(sc.stc & STC.deprecated_); | |
251 | ||
252 | Dsymbol p = sc.parent.pastMixin(); | |
253 | AggregateDeclaration ad = p.isAggregateDeclaration(); | |
254 | if (!ad) | |
255 | { | |
256 | error(dsym.loc, "alias this can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); | |
257 | return; | |
258 | } | |
259 | ||
260 | assert(ad.members); | |
261 | Dsymbol s = ad.search(dsym.loc, dsym.ident); | |
262 | if (!s) | |
263 | { | |
264 | s = sc.search(dsym.loc, dsym.ident, null); | |
265 | if (s) | |
266 | error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); | |
267 | else | |
268 | error(dsym.loc, "undefined identifier `%s`", dsym.ident.toChars()); | |
269 | return; | |
270 | } | |
271 | if (ad.aliasthis && s != ad.aliasthis) | |
272 | { | |
273 | error(dsym.loc, "there can be only one alias this"); | |
274 | return; | |
275 | } | |
276 | ||
277 | /* disable the alias this conversion so the implicit conversion check | |
278 | * doesn't use it. | |
279 | */ | |
280 | ad.aliasthis = null; | |
281 | ||
282 | Dsymbol sx = s; | |
283 | if (sx.isAliasDeclaration()) | |
284 | sx = sx.toAlias(); | |
285 | Declaration d = sx.isDeclaration(); | |
286 | if (d && !d.isTupleDeclaration()) | |
287 | { | |
288 | /* https://issues.dlang.org/show_bug.cgi?id=18429 | |
289 | * | |
290 | * If the identifier in the AliasThis declaration | |
291 | * is defined later and is a voldemort type, we must | |
292 | * perform semantic on the declaration to deduce the type. | |
293 | */ | |
294 | if (!d.type) | |
295 | d.dsymbolSemantic(sc); | |
296 | ||
297 | Type t = d.type; | |
298 | assert(t); | |
299 | if (ad.type.implicitConvTo(t) > MATCH.nomatch) | |
300 | { | |
301 | error(dsym.loc, "alias this is not reachable as `%s` already converts to `%s`", ad.toChars(), t.toChars()); | |
302 | } | |
303 | } | |
304 | ||
305 | dsym.sym = s; | |
306 | // Restore alias this | |
307 | ad.aliasthis = dsym; | |
308 | dsym.semanticRun = PASS.semanticdone; | |
309 | } | |
310 | ||
311 | override void visit(AliasDeclaration dsym) | |
312 | { | |
313 | if (dsym.semanticRun >= PASS.semanticdone) | |
314 | return; | |
315 | assert(dsym.semanticRun <= PASS.semantic); | |
316 | ||
317 | dsym.storage_class |= sc.stc & STC.deprecated_; | |
318 | dsym.visibility = sc.visibility; | |
319 | dsym.userAttribDecl = sc.userAttribDecl; | |
320 | ||
321 | if (!sc.func && dsym.inNonRoot()) | |
322 | return; | |
323 | ||
324 | aliasSemantic(dsym, sc); | |
325 | } | |
326 | ||
327 | override void visit(AliasAssign dsym) | |
328 | { | |
329 | //printf("visit(AliasAssign)\n"); | |
330 | if (dsym.semanticRun >= PASS.semanticdone) | |
331 | return; | |
332 | assert(dsym.semanticRun <= PASS.semantic); | |
333 | ||
334 | if (!sc.func && dsym.inNonRoot()) | |
335 | return; | |
336 | ||
337 | aliasAssignSemantic(dsym, sc); | |
338 | } | |
339 | ||
340 | override void visit(VarDeclaration dsym) | |
341 | { | |
342 | version (none) | |
343 | { | |
344 | printf("VarDeclaration::semantic('%s', parent = '%s') sem = %d\n", | |
345 | dsym.toChars(), sc.parent ? sc.parent.toChars() : null, dsym.semanticRun); | |
346 | printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null"); | |
347 | printf(" stc = x%llx\n", dsym.storage_class); | |
348 | printf(" storage_class = x%llx\n", dsym.storage_class); | |
349 | printf("linkage = %d\n", dsym.linkage); | |
350 | //if (strcmp(toChars(), "mul") == 0) assert(0); | |
351 | } | |
235d5a96 | 352 | //if (semanticRun > PASS.initial) |
5fee5ec3 IB |
353 | // return; |
354 | //semanticRun = PSSsemantic; | |
355 | ||
356 | if (dsym.semanticRun >= PASS.semanticdone) | |
357 | return; | |
358 | ||
359 | if (sc && sc.inunion && sc.inunion.isAnonDeclaration()) | |
360 | dsym.overlapped = true; | |
361 | ||
d7569187 | 362 | dsym.sequenceNumber = global.varSequenceNumber++; |
b7a586be IB |
363 | if (!dsym.isScope()) |
364 | dsym.maybeScope = true; | |
d7569187 | 365 | |
5fee5ec3 IB |
366 | Scope* scx = null; |
367 | if (dsym._scope) | |
368 | { | |
369 | sc = dsym._scope; | |
370 | scx = sc; | |
371 | dsym._scope = null; | |
372 | } | |
373 | ||
374 | if (!sc) | |
375 | return; | |
376 | ||
377 | dsym.semanticRun = PASS.semantic; | |
378 | ||
0fb57034 IB |
379 | // 'static foreach' variables should not inherit scope properties |
380 | // https://issues.dlang.org/show_bug.cgi?id=19482 | |
381 | if ((dsym.storage_class & (STC.foreach_ | STC.local)) == (STC.foreach_ | STC.local)) | |
382 | { | |
5eb9927a | 383 | dsym._linkage = LINK.d; |
0fb57034 IB |
384 | dsym.visibility = Visibility(Visibility.Kind.public_); |
385 | dsym.overlapped = false; // unset because it is modified early on this function | |
386 | dsym.userAttribDecl = null; // unset because it is set by Dsymbol.setScope() | |
387 | } | |
388 | else | |
389 | { | |
390 | /* Pick up storage classes from context, but except synchronized, | |
391 | * override, abstract, and final. | |
392 | */ | |
393 | dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_)); | |
394 | dsym.userAttribDecl = sc.userAttribDecl; | |
395 | dsym.cppnamespace = sc.namespace; | |
5eb9927a | 396 | dsym._linkage = sc.linkage; |
0fb57034 IB |
397 | dsym.visibility = sc.visibility; |
398 | dsym.alignment = sc.alignment(); | |
399 | } | |
400 | ||
5fee5ec3 IB |
401 | if (dsym.storage_class & STC.extern_ && dsym._init) |
402 | dsym.error("extern symbols cannot have initializers"); | |
403 | ||
5fee5ec3 IB |
404 | AggregateDeclaration ad = dsym.isThis(); |
405 | if (ad) | |
406 | dsym.storage_class |= ad.storage_class & STC.TYPECTOR; | |
407 | ||
408 | /* If auto type inference, do the inference | |
409 | */ | |
410 | int inferred = 0; | |
411 | if (!dsym.type) | |
412 | { | |
413 | dsym.inuse++; | |
414 | ||
415 | // Infering the type requires running semantic, | |
416 | // so mark the scope as ctfe if required | |
417 | bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0; | |
418 | if (needctfe) | |
419 | { | |
420 | sc.flags |= SCOPE.condition; | |
421 | sc = sc.startCTFE(); | |
422 | } | |
423 | //printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars()); | |
424 | dsym._init = dsym._init.inferType(sc); | |
235d5a96 | 425 | dsym.type = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0).type; |
5fee5ec3 IB |
426 | if (needctfe) |
427 | sc = sc.endCTFE(); | |
428 | ||
429 | dsym.inuse--; | |
430 | inferred = 1; | |
431 | ||
432 | /* This is a kludge to support the existing syntax for RAII | |
433 | * declarations. | |
434 | */ | |
435 | dsym.storage_class &= ~STC.auto_; | |
436 | dsym.originalType = dsym.type.syntaxCopy(); | |
437 | } | |
438 | else | |
439 | { | |
440 | if (!dsym.originalType) | |
441 | dsym.originalType = dsym.type.syntaxCopy(); | |
442 | ||
443 | /* Prefix function attributes of variable declaration can affect | |
444 | * its type: | |
445 | * pure nothrow void function() fp; | |
446 | * static assert(is(typeof(fp) == void function() pure nothrow)); | |
447 | */ | |
448 | Scope* sc2 = sc.push(); | |
449 | sc2.stc |= (dsym.storage_class & STC.FUNCATTR); | |
450 | dsym.inuse++; | |
451 | dsym.type = dsym.type.typeSemantic(dsym.loc, sc2); | |
452 | dsym.inuse--; | |
453 | sc2.pop(); | |
454 | } | |
455 | //printf(" semantic type = %s\n", dsym.type ? dsym.type.toChars() : "null"); | |
456 | if (dsym.type.ty == Terror) | |
457 | dsym.errors = true; | |
458 | ||
459 | dsym.type.checkDeprecated(dsym.loc, sc); | |
5fee5ec3 IB |
460 | dsym.parent = sc.parent; |
461 | //printf("this = %p, parent = %p, '%s'\n", dsym, dsym.parent, dsym.parent.toChars()); | |
5fee5ec3 IB |
462 | |
463 | /* If scope's alignment is the default, use the type's alignment, | |
464 | * otherwise the scope overrrides. | |
465 | */ | |
0fb57034 | 466 | if (dsym.alignment.isDefault()) |
5fee5ec3 IB |
467 | dsym.alignment = dsym.type.alignment(); // use type's alignment |
468 | ||
469 | //printf("sc.stc = %x\n", sc.stc); | |
470 | //printf("storage_class = x%x\n", storage_class); | |
471 | ||
1027dc45 | 472 | dsym.type.checkComplexTransition(dsym.loc, sc); |
5fee5ec3 IB |
473 | |
474 | // Calculate type size + safety checks | |
610d7898 | 475 | if (dsym.storage_class & STC.gshared && !dsym.isMember()) |
5fee5ec3 | 476 | { |
610d7898 | 477 | sc.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared"); |
5fee5ec3 IB |
478 | } |
479 | ||
480 | Dsymbol parent = dsym.toParent(); | |
481 | ||
482 | Type tb = dsym.type.toBasetype(); | |
483 | Type tbn = tb.baseElemOf(); | |
484 | if (tb.ty == Tvoid && !(dsym.storage_class & STC.lazy_)) | |
485 | { | |
486 | if (inferred) | |
487 | { | |
488 | dsym.error("type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars()); | |
489 | } | |
490 | else | |
491 | dsym.error("variables cannot be of type `void`"); | |
492 | dsym.type = Type.terror; | |
493 | tb = dsym.type; | |
494 | } | |
495 | if (tb.ty == Tfunction) | |
496 | { | |
497 | dsym.error("cannot be declared to be a function"); | |
498 | dsym.type = Type.terror; | |
499 | tb = dsym.type; | |
500 | } | |
501 | if (auto ts = tb.isTypeStruct()) | |
502 | { | |
503 | // Require declarations, except when it's just a reference (as done for pointers) | |
504 | // or when the variable is defined externally | |
505 | if (!ts.sym.members && !(dsym.storage_class & (STC.ref_ | STC.extern_))) | |
506 | { | |
507 | dsym.error("no definition of struct `%s`", ts.toChars()); | |
508 | ||
509 | // Explain why the definition is required when it's part of another type | |
510 | if (!dsym.type.isTypeStruct()) | |
511 | { | |
512 | // Prefer Loc of the dependant type | |
513 | const s = dsym.type.toDsymbol(sc); | |
514 | const loc = (s ? s : dsym).loc; | |
515 | loc.errorSupplemental("required by type `%s`", dsym.type.toChars()); | |
516 | } | |
517 | ||
518 | // Flag variable as error to avoid invalid error messages due to unknown size | |
519 | dsym.type = Type.terror; | |
520 | } | |
521 | } | |
522 | if ((dsym.storage_class & STC.auto_) && !inferred) | |
523 | dsym.error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?"); | |
524 | ||
525 | if (auto tt = tb.isTypeTuple()) | |
526 | { | |
527 | /* Instead, declare variables for each of the tuple elements | |
528 | * and add those. | |
529 | */ | |
530 | size_t nelems = Parameter.dim(tt.arguments); | |
235d5a96 | 531 | Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0) : null; |
5fee5ec3 IB |
532 | if (ie) |
533 | ie = ie.expressionSemantic(sc); | |
534 | if (nelems > 0 && ie) | |
535 | { | |
536 | auto iexps = new Expressions(); | |
537 | iexps.push(ie); | |
538 | auto exps = new Expressions(); | |
539 | for (size_t pos = 0; pos < iexps.dim; pos++) | |
540 | { | |
541 | Lexpand1: | |
542 | Expression e = (*iexps)[pos]; | |
543 | Parameter arg = Parameter.getNth(tt.arguments, pos); | |
544 | arg.type = arg.type.typeSemantic(dsym.loc, sc); | |
545 | //printf("[%d] iexps.dim = %d, ", pos, iexps.dim); | |
31350635 | 546 | //printf("e = (%s %s, %s), ", Token.tochars[e.op], e.toChars(), e.type.toChars()); |
5fee5ec3 IB |
547 | //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); |
548 | ||
549 | if (e != ie) | |
550 | { | |
551 | if (iexps.dim > nelems) | |
552 | goto Lnomatch; | |
553 | if (e.type.implicitConvTo(arg.type)) | |
554 | continue; | |
555 | } | |
556 | ||
557 | if (auto te = e.isTupleExp()) | |
558 | { | |
559 | if (iexps.dim - 1 + te.exps.dim > nelems) | |
560 | goto Lnomatch; | |
561 | ||
562 | iexps.remove(pos); | |
563 | iexps.insert(pos, te.exps); | |
564 | (*iexps)[pos] = Expression.combine(te.e0, (*iexps)[pos]); | |
565 | goto Lexpand1; | |
566 | } | |
567 | else if (isAliasThisTuple(e)) | |
568 | { | |
569 | auto v = copyToTemp(0, "__tup", e); | |
570 | v.dsymbolSemantic(sc); | |
571 | auto ve = new VarExp(dsym.loc, v); | |
572 | ve.type = e.type; | |
573 | ||
574 | exps.setDim(1); | |
575 | (*exps)[0] = ve; | |
576 | expandAliasThisTuples(exps, 0); | |
577 | ||
578 | for (size_t u = 0; u < exps.dim; u++) | |
579 | { | |
580 | Lexpand2: | |
581 | Expression ee = (*exps)[u]; | |
582 | arg = Parameter.getNth(tt.arguments, pos + u); | |
583 | arg.type = arg.type.typeSemantic(dsym.loc, sc); | |
584 | //printf("[%d+%d] exps.dim = %d, ", pos, u, exps.dim); | |
31350635 | 585 | //printf("ee = (%s %s, %s), ", Token.tochars[ee.op], ee.toChars(), ee.type.toChars()); |
5fee5ec3 IB |
586 | //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); |
587 | ||
588 | size_t iexps_dim = iexps.dim - 1 + exps.dim; | |
589 | if (iexps_dim > nelems) | |
590 | goto Lnomatch; | |
591 | if (ee.type.implicitConvTo(arg.type)) | |
592 | continue; | |
593 | ||
594 | if (expandAliasThisTuples(exps, u) != -1) | |
595 | goto Lexpand2; | |
596 | } | |
597 | ||
598 | if ((*exps)[0] != ve) | |
599 | { | |
600 | Expression e0 = (*exps)[0]; | |
601 | (*exps)[0] = new CommaExp(dsym.loc, new DeclarationExp(dsym.loc, v), e0); | |
602 | (*exps)[0].type = e0.type; | |
603 | ||
604 | iexps.remove(pos); | |
605 | iexps.insert(pos, exps); | |
606 | goto Lexpand1; | |
607 | } | |
608 | } | |
609 | } | |
610 | if (iexps.dim < nelems) | |
611 | goto Lnomatch; | |
612 | ||
613 | ie = new TupleExp(dsym._init.loc, iexps); | |
614 | } | |
615 | Lnomatch: | |
616 | ||
9c7d5e88 | 617 | if (ie && ie.op == EXP.tuple) |
5fee5ec3 IB |
618 | { |
619 | auto te = ie.isTupleExp(); | |
620 | size_t tedim = te.exps.dim; | |
621 | if (tedim != nelems) | |
622 | { | |
623 | error(dsym.loc, "tuple of %d elements cannot be assigned to tuple of %d elements", cast(int)tedim, cast(int)nelems); | |
624 | for (size_t u = tedim; u < nelems; u++) // fill dummy expression | |
625 | te.exps.push(ErrorExp.get()); | |
626 | } | |
627 | } | |
628 | ||
629 | auto exps = new Objects(nelems); | |
630 | for (size_t i = 0; i < nelems; i++) | |
631 | { | |
632 | Parameter arg = Parameter.getNth(tt.arguments, i); | |
633 | ||
634 | OutBuffer buf; | |
635 | buf.printf("__%s_field_%llu", dsym.ident.toChars(), cast(ulong)i); | |
636 | auto id = Identifier.idPool(buf[]); | |
637 | ||
638 | Initializer ti; | |
639 | if (ie) | |
640 | { | |
641 | Expression einit = ie; | |
642 | if (auto te = ie.isTupleExp()) | |
643 | { | |
644 | einit = (*te.exps)[i]; | |
645 | if (i == 0) | |
646 | einit = Expression.combine(te.e0, einit); | |
647 | } | |
648 | ti = new ExpInitializer(einit.loc, einit); | |
649 | } | |
650 | else | |
651 | ti = dsym._init ? dsym._init.syntaxCopy() : null; | |
652 | ||
d97f3bca | 653 | StorageClass storage_class = STC.temp | dsym.storage_class; |
5fee5ec3 IB |
654 | if ((dsym.storage_class & STC.parameter) && (arg.storageClass & STC.parameter)) |
655 | storage_class |= arg.storageClass; | |
656 | auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class); | |
657 | //printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars()); | |
9c7d5e88 IB |
658 | v.overlapped = dsym.overlapped; |
659 | ||
5fee5ec3 IB |
660 | v.dsymbolSemantic(sc); |
661 | ||
d97f3bca | 662 | Expression e = new VarExp(dsym.loc, v); |
5fee5ec3 IB |
663 | (*exps)[i] = e; |
664 | } | |
665 | auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps); | |
666 | v2.parent = dsym.parent; | |
667 | v2.isexp = true; | |
668 | dsym.aliassym = v2; | |
669 | dsym.semanticRun = PASS.semanticdone; | |
670 | return; | |
671 | } | |
672 | ||
673 | /* Storage class can modify the type | |
674 | */ | |
675 | dsym.type = dsym.type.addStorageClass(dsym.storage_class); | |
676 | ||
677 | /* Adjust storage class to reflect type | |
678 | */ | |
679 | if (dsym.type.isConst()) | |
680 | { | |
681 | dsym.storage_class |= STC.const_; | |
682 | if (dsym.type.isShared()) | |
683 | dsym.storage_class |= STC.shared_; | |
684 | } | |
685 | else if (dsym.type.isImmutable()) | |
686 | dsym.storage_class |= STC.immutable_; | |
687 | else if (dsym.type.isShared()) | |
688 | dsym.storage_class |= STC.shared_; | |
689 | else if (dsym.type.isWild()) | |
690 | dsym.storage_class |= STC.wild; | |
691 | ||
692 | if (StorageClass stc = dsym.storage_class & (STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_)) | |
693 | { | |
694 | if (stc == STC.final_) | |
695 | dsym.error("cannot be `final`, perhaps you meant `const`?"); | |
696 | else | |
697 | { | |
698 | OutBuffer buf; | |
699 | stcToBuffer(&buf, stc); | |
700 | dsym.error("cannot be `%s`", buf.peekChars()); | |
701 | } | |
702 | dsym.storage_class &= ~stc; // strip off | |
703 | } | |
704 | ||
705 | // At this point we can add `scope` to the STC instead of `in`, | |
706 | // because we are never going to use this variable's STC for user messages | |
707 | if (dsym.storage_class & STC.in_ && global.params.previewIn) | |
708 | dsym.storage_class |= STC.scope_; | |
709 | ||
710 | if (dsym.storage_class & STC.scope_) | |
711 | { | |
fbdaa581 | 712 | StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.gshared); |
5fee5ec3 IB |
713 | if (stc) |
714 | { | |
715 | OutBuffer buf; | |
716 | stcToBuffer(&buf, stc); | |
717 | dsym.error("cannot be `scope` and `%s`", buf.peekChars()); | |
718 | } | |
719 | else if (dsym.isMember()) | |
720 | { | |
721 | dsym.error("field cannot be `scope`"); | |
722 | } | |
723 | else if (!dsym.type.hasPointers()) | |
724 | { | |
725 | dsym.storage_class &= ~STC.scope_; // silently ignore; may occur in generic code | |
d97f3bca IB |
726 | // https://issues.dlang.org/show_bug.cgi?id=23168 |
727 | if (dsym.storage_class & STC.returnScope) | |
728 | { | |
729 | dsym.storage_class &= ~(STC.return_ | STC.returnScope); | |
730 | } | |
5fee5ec3 IB |
731 | } |
732 | } | |
733 | ||
fbdaa581 | 734 | if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.gshared | STC.ctfe)) |
5fee5ec3 IB |
735 | { |
736 | } | |
737 | else | |
738 | { | |
739 | AggregateDeclaration aad = parent.isAggregateDeclaration(); | |
740 | if (aad) | |
741 | { | |
742 | if (global.params.vfield && dsym.storage_class & (STC.const_ | STC.immutable_) && dsym._init && !dsym._init.isVoidInitializer()) | |
743 | { | |
744 | const(char)* s = (dsym.storage_class & STC.immutable_) ? "immutable" : "const"; | |
745 | message(dsym.loc, "`%s.%s` is `%s` field", ad.toPrettyChars(), dsym.toChars(), s); | |
746 | } | |
747 | dsym.storage_class |= STC.field; | |
748 | if (auto ts = tbn.isTypeStruct()) | |
749 | if (ts.sym.noDefaultCtor) | |
750 | { | |
751 | if (!dsym.isThisDeclaration() && !dsym._init) | |
752 | aad.noDefaultCtor = true; | |
753 | } | |
754 | } | |
755 | ||
756 | InterfaceDeclaration id = parent.isInterfaceDeclaration(); | |
757 | if (id) | |
758 | { | |
759 | dsym.error("field not allowed in interface"); | |
760 | } | |
761 | else if (aad && aad.sizeok == Sizeok.done) | |
762 | { | |
763 | dsym.error("cannot be further field because it will change the determined %s size", aad.toChars()); | |
764 | } | |
765 | ||
766 | /* Templates cannot add fields to aggregates | |
767 | */ | |
768 | TemplateInstance ti = parent.isTemplateInstance(); | |
769 | if (ti) | |
770 | { | |
771 | // Take care of nested templates | |
772 | while (1) | |
773 | { | |
774 | TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); | |
775 | if (!ti2) | |
776 | break; | |
777 | ti = ti2; | |
778 | } | |
779 | // If it's a member template | |
780 | AggregateDeclaration ad2 = ti.tempdecl.isMember(); | |
781 | if (ad2 && dsym.storage_class != STC.undefined_) | |
782 | { | |
783 | dsym.error("cannot use template to add field to aggregate `%s`", ad2.toChars()); | |
784 | } | |
785 | } | |
786 | } | |
787 | ||
788 | if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This) | |
789 | { | |
790 | dsym.error("only parameters or `foreach` declarations can be `ref`"); | |
791 | } | |
792 | ||
793 | if (dsym.type.hasWild()) | |
794 | { | |
fbdaa581 | 795 | if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg()) |
5fee5ec3 IB |
796 | { |
797 | dsym.error("only parameters or stack based variables can be `inout`"); | |
798 | } | |
799 | FuncDeclaration func = sc.func; | |
800 | if (func) | |
801 | { | |
802 | if (func.fes) | |
803 | func = func.fes.func; | |
804 | bool isWild = false; | |
805 | for (FuncDeclaration fd = func; fd; fd = fd.toParentDecl().isFuncDeclaration()) | |
806 | { | |
807 | if (fd.type.isTypeFunction().iswild) | |
808 | { | |
809 | isWild = true; | |
810 | break; | |
811 | } | |
812 | } | |
813 | if (!isWild) | |
814 | { | |
815 | dsym.error("`inout` variables can only be declared inside `inout` functions"); | |
816 | } | |
817 | } | |
818 | } | |
819 | ||
820 | if (!(dsym.storage_class & (STC.ctfe | STC.extern_ | STC.ref_ | STC.result)) && | |
821 | tbn.ty == Tstruct && tbn.isTypeStruct().sym.noDefaultCtor) | |
822 | { | |
823 | if (!dsym._init) | |
824 | { | |
825 | if (dsym.isField()) | |
826 | { | |
827 | /* For fields, we'll check the constructor later to make sure it is initialized | |
828 | */ | |
829 | dsym.storage_class |= STC.nodefaultctor; | |
830 | } | |
831 | else if (dsym.storage_class & STC.parameter) | |
832 | { | |
833 | } | |
834 | else | |
835 | dsym.error("default construction is disabled for type `%s`", dsym.type.toChars()); | |
836 | } | |
837 | } | |
838 | ||
839 | FuncDeclaration fd = parent.isFuncDeclaration(); | |
840 | if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor)) | |
841 | { | |
fbdaa581 | 842 | if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.gshared) || !fd) |
5fee5ec3 IB |
843 | { |
844 | dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`"); | |
845 | } | |
846 | ||
6384eff5 | 847 | // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint |
5fee5ec3 IB |
848 | // Deprecated in 2.087 |
849 | // Remove this when the feature is removed from the language | |
6384eff5 | 850 | if (!(dsym.storage_class & STC.scope_)) |
5fee5ec3 IB |
851 | { |
852 | if (!(dsym.storage_class & STC.parameter) && dsym.ident != Id.withSym) | |
853 | dsym.error("reference to `scope class` must be `scope`"); | |
854 | } | |
855 | } | |
856 | ||
857 | // Calculate type size + safety checks | |
610d7898 | 858 | if (1) |
5fee5ec3 IB |
859 | { |
860 | if (dsym._init && dsym._init.isVoidInitializer() && | |
861 | (dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size | |
862 | { | |
5eb9927a | 863 | if (dsym.type.hasPointers()) |
610d7898 | 864 | sc.setUnsafe(false, dsym.loc, |
5eb9927a IB |
865 | "`void` initializers for pointers not allowed in safe functions"); |
866 | else | |
610d7898 | 867 | sc.setUnsafe(false, dsym.loc, |
5eb9927a | 868 | "`void` initializers for structs with invariants are not allowed in safe functions"); |
5fee5ec3 IB |
869 | } |
870 | else if (!dsym._init && | |
fbdaa581 | 871 | !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) && |
5fee5ec3 IB |
872 | dsym.type.hasVoidInitPointers()) |
873 | { | |
610d7898 | 874 | sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions"); |
5fee5ec3 IB |
875 | } |
876 | } | |
877 | ||
878 | if ((!dsym._init || dsym._init.isVoidInitializer) && !fd) | |
879 | { | |
880 | // If not mutable, initializable by constructor only | |
9c7d5e88 | 881 | dsym.setInCtorOnly = true; |
5fee5ec3 IB |
882 | } |
883 | ||
884 | if (dsym._init) | |
9c7d5e88 | 885 | { } // remember we had an explicit initializer |
5fee5ec3 IB |
886 | else if (dsym.storage_class & STC.manifest) |
887 | dsym.error("manifest constants must have initializers"); | |
888 | ||
5eb9927a IB |
889 | // Don't allow non-extern, non-__gshared variables to be interfaced with C++ |
890 | if (dsym._linkage == LINK.cpp && !(dsym.storage_class & (STC.ctfe | STC.extern_ | STC.gshared)) && dsym.isDataseg()) | |
891 | { | |
892 | const char* p = (dsym.storage_class & STC.shared_) ? "shared" : "static"; | |
893 | dsym.error("cannot have `extern(C++)` linkage because it is `%s`", p); | |
894 | errorSupplemental(dsym.loc, "perhaps declare it as `__gshared` instead"); | |
895 | dsym.errors = true; | |
896 | } | |
897 | ||
5fee5ec3 | 898 | bool isBlit = false; |
fbdaa581 | 899 | uinteger_t sz; |
fd43568c IB |
900 | if (sc.flags & SCOPE.Cfile && !dsym._init) |
901 | { | |
902 | addDefaultCInitializer(dsym); | |
903 | } | |
5fee5ec3 IB |
904 | if (!dsym._init && |
905 | !(dsym.storage_class & (STC.static_ | STC.gshared | STC.extern_)) && | |
906 | fd && | |
907 | (!(dsym.storage_class & (STC.field | STC.in_ | STC.foreach_ | STC.parameter | STC.result)) || | |
908 | (dsym.storage_class & STC.out_)) && | |
909 | (sz = dsym.type.size()) != 0) | |
910 | { | |
911 | // Provide a default initializer | |
912 | ||
fd43568c | 913 | //printf("Providing default initializer for '%s'\n", dsym.toChars()); |
5fee5ec3 IB |
914 | if (sz == SIZE_INVALID && dsym.type.ty != Terror) |
915 | dsym.error("size of type `%s` is invalid", dsym.type.toChars()); | |
916 | ||
917 | Type tv = dsym.type; | |
918 | while (tv.ty == Tsarray) // Don't skip Tenum | |
919 | tv = tv.nextOf(); | |
920 | if (tv.needsNested()) | |
921 | { | |
922 | /* Nested struct requires valid enclosing frame pointer. | |
923 | * In StructLiteralExp::toElem(), it's calculated. | |
924 | */ | |
925 | assert(tbn.ty == Tstruct); | |
926 | checkFrameAccess(dsym.loc, sc, tbn.isTypeStruct().sym); | |
927 | ||
928 | Expression e = tv.defaultInitLiteral(dsym.loc); | |
929 | e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e); | |
930 | e = e.expressionSemantic(sc); | |
931 | dsym._init = new ExpInitializer(dsym.loc, e); | |
932 | goto Ldtor; | |
933 | } | |
934 | if (tv.ty == Tstruct && tv.isTypeStruct().sym.zeroInit) | |
935 | { | |
936 | /* If a struct is all zeros, as a special case | |
937 | * set its initializer to the integer 0. | |
938 | * In AssignExp::toElem(), we check for this and issue | |
939 | * a memset() to initialize the struct. | |
940 | * Must do same check in interpreter. | |
941 | */ | |
942 | Expression e = IntegerExp.literal!0; | |
943 | e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e); | |
944 | e.type = dsym.type; // don't type check this, it would fail | |
945 | dsym._init = new ExpInitializer(dsym.loc, e); | |
946 | goto Ldtor; | |
947 | } | |
948 | if (dsym.type.baseElemOf().ty == Tvoid) | |
949 | { | |
950 | dsym.error("`%s` does not have a default initializer", dsym.type.toChars()); | |
951 | } | |
952 | else if (auto e = dsym.type.defaultInit(dsym.loc)) | |
953 | { | |
954 | dsym._init = new ExpInitializer(dsym.loc, e); | |
955 | } | |
956 | ||
957 | // Default initializer is always a blit | |
958 | isBlit = true; | |
959 | } | |
960 | if (dsym._init) | |
961 | { | |
962 | sc = sc.push(); | |
963 | sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable); | |
964 | ||
0fb57034 IB |
965 | if (sc.flags & SCOPE.Cfile && |
966 | dsym.type.isTypeSArray() && | |
967 | dsym.type.isTypeSArray().isIncomplete() && | |
968 | dsym._init.isVoidInitializer() && | |
969 | !(dsym.storage_class & STC.field)) | |
970 | { | |
971 | dsym.error("incomplete array type must have initializer"); | |
972 | } | |
973 | ||
5fee5ec3 IB |
974 | ExpInitializer ei = dsym._init.isExpInitializer(); |
975 | ||
976 | if (ei) // https://issues.dlang.org/show_bug.cgi?id=13424 | |
977 | // Preset the required type to fail in FuncLiteralDeclaration::semantic3 | |
978 | ei.exp = inferType(ei.exp, dsym.type); | |
979 | ||
980 | // If inside function, there is no semantic3() call | |
981 | if (sc.func || sc.intypeof == 1) | |
982 | { | |
983 | // If local variable, use AssignExp to handle all the various | |
984 | // possibilities. | |
fbdaa581 | 985 | if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer()) |
5fee5ec3 | 986 | { |
c8dfa79c | 987 | //printf("fd = '%s', var = '%s'\n", fd.toChars(), dsym.toChars()); |
5fee5ec3 IB |
988 | if (!ei) |
989 | { | |
990 | ArrayInitializer ai = dsym._init.isArrayInitializer(); | |
991 | Expression e; | |
992 | if (ai && tb.ty == Taarray) | |
993 | e = ai.toAssocArrayLiteral(); | |
994 | else | |
235d5a96 | 995 | e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); |
5fee5ec3 IB |
996 | if (!e) |
997 | { | |
998 | // Run semantic, but don't need to interpret | |
999 | dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret); | |
235d5a96 | 1000 | e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); |
5fee5ec3 IB |
1001 | if (!e) |
1002 | { | |
1003 | dsym.error("is not a static and cannot have static initializer"); | |
1004 | e = ErrorExp.get(); | |
1005 | } | |
1006 | } | |
1007 | ei = new ExpInitializer(dsym._init.loc, e); | |
1008 | dsym._init = ei; | |
1009 | } | |
0fb57034 IB |
1010 | else if (sc.flags & SCOPE.Cfile && dsym.type.isTypeSArray() && |
1011 | dsym.type.isTypeSArray().isIncomplete()) | |
1012 | { | |
1013 | // C11 6.7.9-22 determine the size of the incomplete array, | |
1014 | // or issue an error that the initializer is invalid. | |
1015 | dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret); | |
1016 | } | |
5fee5ec3 | 1017 | |
5fee5ec3 IB |
1018 | if (ei && dsym.isScope()) |
1019 | { | |
1020 | Expression ex = ei.exp.lastComma(); | |
9c7d5e88 | 1021 | if (ex.op == EXP.blit || ex.op == EXP.construct) |
5fee5ec3 IB |
1022 | ex = (cast(AssignExp)ex).e2; |
1023 | if (auto ne = ex.isNewExp()) | |
1024 | { | |
1025 | // See if initializer is a NewExp that can be allocated on the stack | |
1026 | if (dsym.type.toBasetype().ty == Tclass) | |
1027 | { | |
6384eff5 IB |
1028 | ne.onstack = 1; |
1029 | dsym.onstack = true; | |
5fee5ec3 IB |
1030 | } |
1031 | } | |
1032 | else if (auto fe = ex.isFuncExp()) | |
1033 | { | |
1034 | // or a delegate that doesn't escape a reference to the function | |
1035 | FuncDeclaration f = fe.fd; | |
1036 | if (f.tookAddressOf) | |
1037 | f.tookAddressOf--; | |
1038 | } | |
1039 | } | |
c8dfa79c IB |
1040 | |
1041 | Expression exp = ei.exp; | |
1042 | Expression e1 = new VarExp(dsym.loc, dsym); | |
1043 | if (isBlit) | |
1044 | exp = new BlitExp(dsym.loc, e1, exp); | |
1045 | else | |
1046 | exp = new ConstructExp(dsym.loc, e1, exp); | |
1047 | dsym.canassign++; | |
1048 | exp = exp.expressionSemantic(sc); | |
1049 | dsym.canassign--; | |
1050 | exp = exp.optimize(WANTvalue); | |
1051 | if (exp.op == EXP.error) | |
1052 | { | |
1053 | dsym._init = new ErrorInitializer(); | |
1054 | ei = null; | |
1055 | } | |
1056 | else | |
1057 | ei.exp = exp; | |
5fee5ec3 IB |
1058 | } |
1059 | else | |
1060 | { | |
1061 | // https://issues.dlang.org/show_bug.cgi?id=14166 | |
1062 | // Don't run CTFE for the temporary variables inside typeof | |
1063 | dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); | |
1064 | const init_err = dsym._init.isExpInitializer(); | |
9c7d5e88 | 1065 | if (init_err && init_err.exp.op == EXP.showCtfeContext) |
5fee5ec3 IB |
1066 | { |
1067 | errorSupplemental(dsym.loc, "compile time context created here"); | |
1068 | } | |
1069 | } | |
1070 | } | |
1071 | else if (parent.isAggregateDeclaration()) | |
1072 | { | |
1073 | dsym._scope = scx ? scx : sc.copy(); | |
1074 | dsym._scope.setNoFree(); | |
1075 | } | |
1076 | else if (dsym.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) || | |
1077 | dsym.type.isConst() || dsym.type.isImmutable() || | |
1078 | sc.flags & SCOPE.Cfile) | |
1079 | { | |
1080 | /* Because we may need the results of a const declaration in a | |
1081 | * subsequent type, such as an array dimension, before semantic2() | |
1082 | * gets ordinarily run, try to run semantic2() now. | |
1083 | * If a C array is of unknown size, the initializer can provide the size. Do this | |
1084 | * eagerly because C does it eagerly. | |
1085 | * Ignore failure. | |
1086 | */ | |
1087 | if (!inferred) | |
1088 | { | |
1089 | uint errors = global.errors; | |
1090 | dsym.inuse++; | |
1091 | // Bug 20549. Don't try this on modules or packages, syntaxCopy | |
1092 | // could crash (inf. recursion) on a mod/pkg referencing itself | |
9c7d5e88 | 1093 | if (ei && (ei.exp.op != EXP.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage())) |
5fee5ec3 | 1094 | { |
0fb57034 IB |
1095 | if (ei.exp.type) |
1096 | { | |
1097 | // If exp is already resolved we are done, our original init exp | |
1098 | // could have a type painting that we need to respect | |
1099 | // e.g. ['a'] typed as string, or [['z'], ""] as string[] | |
1100 | // See https://issues.dlang.org/show_bug.cgi?id=15711 | |
1101 | } | |
1102 | else | |
1103 | { | |
1104 | Expression exp = ei.exp.syntaxCopy(); | |
1105 | ||
1106 | bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest); | |
1107 | if (needctfe) | |
1108 | sc = sc.startCTFE(); | |
1109 | exp = exp.expressionSemantic(sc); | |
1110 | exp = resolveProperties(sc, exp); | |
1111 | if (needctfe) | |
1112 | sc = sc.endCTFE(); | |
1113 | ei.exp = exp; | |
1114 | } | |
5fee5ec3 IB |
1115 | |
1116 | Type tb2 = dsym.type.toBasetype(); | |
0fb57034 | 1117 | Type ti = ei.exp.type.toBasetype(); |
5fee5ec3 IB |
1118 | |
1119 | /* The problem is the following code: | |
1120 | * struct CopyTest { | |
1121 | * double x; | |
1122 | * this(double a) { x = a * 10.0;} | |
1123 | * this(this) { x += 2.0; } | |
1124 | * } | |
1125 | * const CopyTest z = CopyTest(5.3); // ok | |
1126 | * const CopyTest w = z; // not ok, postblit not run | |
1127 | * static assert(w.x == 55.0); | |
1128 | * because the postblit doesn't get run on the initialization of w. | |
1129 | */ | |
1130 | if (auto ts = ti.isTypeStruct()) | |
1131 | { | |
1132 | StructDeclaration sd = ts.sym; | |
1133 | /* Look to see if initializer involves a copy constructor | |
1134 | * (which implies a postblit) | |
1135 | */ | |
1136 | // there is a copy constructor | |
1137 | // and exp is the same struct | |
1138 | if (sd.postblit && tb2.toDsymbol(null) == sd) | |
1139 | { | |
1140 | // The only allowable initializer is a (non-copy) constructor | |
0fb57034 | 1141 | if (ei.exp.isLvalue()) |
5fee5ec3 IB |
1142 | dsym.error("of type struct `%s` uses `this(this)`, which is not allowed in static initialization", tb2.toChars()); |
1143 | } | |
1144 | } | |
5fee5ec3 IB |
1145 | } |
1146 | ||
1147 | dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret); | |
1148 | dsym.inuse--; | |
1149 | if (global.errors > errors) | |
1150 | { | |
1151 | dsym._init = new ErrorInitializer(); | |
1152 | dsym.type = Type.terror; | |
1153 | } | |
1154 | } | |
1155 | else | |
1156 | { | |
1157 | dsym._scope = scx ? scx : sc.copy(); | |
1158 | dsym._scope.setNoFree(); | |
1159 | } | |
1160 | } | |
1161 | sc = sc.pop(); | |
1162 | } | |
1163 | ||
1164 | Ldtor: | |
1165 | /* Build code to execute destruction, if necessary | |
1166 | */ | |
1167 | dsym.edtor = dsym.callScopeDtor(sc); | |
1168 | if (dsym.edtor) | |
1169 | { | |
5fee5ec3 IB |
1170 | if (sc.func && dsym.storage_class & (STC.static_ | STC.gshared)) |
1171 | dsym.edtor = dsym.edtor.expressionSemantic(sc._module._scope); | |
1172 | else | |
1173 | dsym.edtor = dsym.edtor.expressionSemantic(sc); | |
1174 | ||
1175 | version (none) | |
1176 | { | |
1177 | // currently disabled because of std.stdio.stdin, stdout and stderr | |
1178 | if (dsym.isDataseg() && !(dsym.storage_class & STC.extern_)) | |
1179 | dsym.error("static storage variables cannot have destructors"); | |
1180 | } | |
1181 | } | |
1182 | ||
1183 | dsym.semanticRun = PASS.semanticdone; | |
1184 | ||
1185 | if (dsym.type.toBasetype().ty == Terror) | |
1186 | dsym.errors = true; | |
1187 | ||
1188 | if(sc.scopesym && !sc.scopesym.isAggregateDeclaration()) | |
1189 | { | |
1190 | for (ScopeDsymbol sym = sc.scopesym; sym && dsym.endlinnum == 0; | |
1191 | sym = sym.parent ? sym.parent.isScopeDsymbol() : null) | |
1192 | dsym.endlinnum = sym.endlinnum; | |
1193 | } | |
1194 | } | |
1195 | ||
1196 | override void visit(TypeInfoDeclaration dsym) | |
1197 | { | |
5eb9927a | 1198 | assert(dsym._linkage == LINK.c); |
5fee5ec3 IB |
1199 | } |
1200 | ||
1201 | override void visit(BitFieldDeclaration dsym) | |
1202 | { | |
1203 | //printf("BitField::semantic('%s') %s\n", toPrettyChars(), id.toChars()); | |
1204 | if (dsym.semanticRun >= PASS.semanticdone) | |
1205 | return; | |
1206 | ||
1207 | visit(cast(VarDeclaration)dsym); | |
1208 | if (dsym.errors) | |
1209 | return; | |
1210 | ||
5eb9927a IB |
1211 | if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration()) |
1212 | { | |
1213 | dsym.error("bit-field must be member of struct, union, or class"); | |
1214 | } | |
1215 | ||
5fee5ec3 IB |
1216 | sc = sc.startCTFE(); |
1217 | auto width = dsym.width.expressionSemantic(sc); | |
1218 | sc = sc.endCTFE(); | |
1219 | width = width.ctfeInterpret(); | |
1220 | if (!dsym.type.isintegral()) | |
1221 | { | |
1222 | // C11 6.7.2.1-5 | |
1223 | width.error("bit-field type `%s` is not an integer type", dsym.type.toChars()); | |
1224 | dsym.errors = true; | |
1225 | } | |
1226 | if (!width.isIntegerExp()) | |
1227 | { | |
1228 | width.error("bit-field width `%s` is not an integer constant", dsym.width.toChars()); | |
1229 | dsym.errors = true; | |
1230 | } | |
1231 | const uwidth = width.toInteger(); // uwidth is unsigned | |
1232 | if (uwidth == 0 && !dsym.isAnonymous()) | |
1233 | { | |
1234 | width.error("bit-field `%s` has zero width", dsym.toChars()); | |
1235 | dsym.errors = true; | |
1236 | } | |
9c7d5e88 IB |
1237 | const sz = dsym.type.size(); |
1238 | if (sz == SIZE_INVALID) | |
1239 | dsym.errors = true; | |
1240 | const max_width = sz * 8; | |
5fee5ec3 IB |
1241 | if (uwidth > max_width) |
1242 | { | |
1243 | width.error("width `%lld` of bit-field `%s` does not fit in type `%s`", cast(long)uwidth, dsym.toChars(), dsym.type.toChars()); | |
1244 | dsym.errors = true; | |
1245 | } | |
1246 | dsym.fieldWidth = cast(uint)uwidth; | |
1247 | } | |
1248 | ||
1249 | override void visit(Import imp) | |
1250 | { | |
5eb9927a IB |
1251 | static if (LOG) |
1252 | { | |
1253 | printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars()); | |
1254 | scope(exit) | |
1255 | printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); | |
1256 | } | |
235d5a96 | 1257 | if (imp.semanticRun > PASS.initial) |
5fee5ec3 IB |
1258 | return; |
1259 | ||
1260 | if (imp._scope) | |
1261 | { | |
1262 | sc = imp._scope; | |
1263 | imp._scope = null; | |
1264 | } | |
1265 | if (!sc) | |
1266 | return; | |
1267 | ||
1268 | imp.parent = sc.parent; | |
1269 | ||
1270 | imp.semanticRun = PASS.semantic; | |
1271 | ||
1272 | // Load if not already done so | |
1273 | bool loadErrored = false; | |
1274 | if (!imp.mod) | |
1275 | { | |
1276 | loadErrored = imp.load(sc); | |
1277 | if (imp.mod) | |
1278 | { | |
1279 | imp.mod.importAll(null); | |
1280 | imp.mod.checkImportDeprecation(imp.loc, sc); | |
1281 | } | |
1282 | } | |
1283 | if (imp.mod) | |
1284 | { | |
1285 | // Modules need a list of each imported module | |
1286 | ||
1287 | // if inside a template instantiation, the instantianting | |
1288 | // module gets the import. | |
1289 | // https://issues.dlang.org/show_bug.cgi?id=17181 | |
1290 | Module importer = sc._module; | |
1291 | if (sc.minst && sc.tinst) | |
1292 | { | |
1293 | importer = sc.minst; | |
1294 | if (!sc.tinst.importedModules.contains(imp.mod)) | |
1295 | sc.tinst.importedModules.push(imp.mod); | |
1296 | } | |
1297 | //printf("%s imports %s\n", importer.toChars(), imp.mod.toChars()); | |
1298 | if (!importer.aimports.contains(imp.mod)) | |
1299 | importer.aimports.push(imp.mod); | |
1300 | ||
1301 | if (sc.explicitVisibility) | |
1302 | imp.visibility = sc.visibility; | |
1303 | ||
1304 | if (!imp.aliasId && !imp.names.dim) // neither a selective nor a renamed import | |
1305 | { | |
1306 | ScopeDsymbol scopesym = sc.getScopesym(); | |
1307 | ||
1308 | if (!imp.isstatic) | |
1309 | { | |
1310 | scopesym.importScope(imp.mod, imp.visibility); | |
1311 | } | |
1312 | ||
1313 | ||
1314 | imp.addPackageAccess(scopesym); | |
1315 | } | |
1316 | ||
1317 | if (!loadErrored) | |
1318 | { | |
1319 | imp.mod.dsymbolSemantic(null); | |
1320 | } | |
1321 | ||
1322 | if (imp.mod.needmoduleinfo) | |
1323 | { | |
1324 | //printf("module4 %s because of %s\n", importer.toChars(), imp.mod.toChars()); | |
1325 | importer.needmoduleinfo = 1; | |
1326 | } | |
1327 | ||
1328 | sc = sc.push(imp.mod); | |
1329 | sc.visibility = imp.visibility; | |
1330 | for (size_t i = 0; i < imp.aliasdecls.dim; i++) | |
1331 | { | |
1332 | AliasDeclaration ad = imp.aliasdecls[i]; | |
1333 | //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope); | |
1334 | Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports); | |
1335 | if (sym) | |
1336 | { | |
1337 | import dmd.access : symbolIsVisible; | |
1338 | if (!symbolIsVisible(sc, sym)) | |
1339 | imp.mod.error(imp.loc, "member `%s` is not visible from module `%s`", | |
1340 | imp.names[i].toChars(), sc._module.toChars()); | |
1341 | ad.dsymbolSemantic(sc); | |
1342 | // If the import declaration is in non-root module, | |
1343 | // analysis of the aliased symbol is deferred. | |
1344 | // Therefore, don't see the ad.aliassym or ad.type here. | |
1345 | } | |
1346 | else | |
1347 | { | |
1348 | Dsymbol s = imp.mod.search_correct(imp.names[i]); | |
1349 | if (s) | |
1350 | imp.mod.error(imp.loc, "import `%s` not found, did you mean %s `%s`?", imp.names[i].toChars(), s.kind(), s.toPrettyChars()); | |
1351 | else | |
1352 | imp.mod.error(imp.loc, "import `%s` not found", imp.names[i].toChars()); | |
1353 | ad.type = Type.terror; | |
1354 | } | |
1355 | } | |
1356 | sc = sc.pop(); | |
1357 | } | |
1358 | ||
1359 | imp.semanticRun = PASS.semanticdone; | |
1360 | ||
1361 | // object self-imports itself, so skip that | |
1362 | // https://issues.dlang.org/show_bug.cgi?id=7547 | |
1363 | // don't list pseudo modules __entrypoint.d, __main.d | |
1364 | // https://issues.dlang.org/show_bug.cgi?id=11117 | |
1365 | // https://issues.dlang.org/show_bug.cgi?id=11164 | |
5eb9927a IB |
1366 | if (global.params.moduleDeps.buffer is null || (imp.id == Id.object && sc._module.ident == Id.object) || |
1367 | strcmp(sc._module.ident.toChars(), "__main") == 0) | |
1368 | return; | |
1369 | ||
1370 | /* The grammar of the file is: | |
1371 | * ImportDeclaration | |
1372 | * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " | |
1373 | * ModuleAliasIdentifier ] "\n" | |
1374 | * | |
1375 | * BasicImportDeclaration | |
1376 | * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string" | |
1377 | * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" | |
1378 | * | |
1379 | * FilePath | |
1380 | * - any string with '(', ')' and '\' escaped with the '\' character | |
1381 | */ | |
1382 | OutBuffer* ob = global.params.moduleDeps.buffer; | |
1383 | Module imod = sc._module; | |
1384 | if (!global.params.moduleDeps.name) | |
1385 | ob.writestring("depsImport "); | |
1386 | ob.writestring(imod.toPrettyChars()); | |
1387 | ob.writestring(" ("); | |
1388 | escapePath(ob, imod.srcfile.toChars()); | |
1389 | ob.writestring(") : "); | |
1390 | // use visibility instead of sc.visibility because it couldn't be | |
1391 | // resolved yet, see the comment above | |
1392 | visibilityToBuffer(ob, imp.visibility); | |
1393 | ob.writeByte(' '); | |
1394 | if (imp.isstatic) | |
1395 | { | |
1396 | stcToBuffer(ob, STC.static_); | |
5fee5ec3 | 1397 | ob.writeByte(' '); |
5eb9927a IB |
1398 | } |
1399 | ob.writestring(": "); | |
1400 | foreach (pid; imp.packages) | |
1401 | { | |
1402 | ob.printf("%s.", pid.toChars()); | |
1403 | } | |
1404 | ob.writestring(imp.id.toString()); | |
1405 | ob.writestring(" ("); | |
1406 | if (imp.mod) | |
1407 | escapePath(ob, imp.mod.srcfile.toChars()); | |
1408 | else | |
1409 | ob.writestring("???"); | |
1410 | ob.writeByte(')'); | |
1411 | foreach (i, name; imp.names) | |
1412 | { | |
1413 | if (i == 0) | |
1414 | ob.writeByte(':'); | |
5fee5ec3 | 1415 | else |
5eb9927a IB |
1416 | ob.writeByte(','); |
1417 | Identifier _alias = imp.aliases[i]; | |
1418 | if (!_alias) | |
5fee5ec3 | 1419 | { |
5eb9927a IB |
1420 | ob.printf("%s", name.toChars()); |
1421 | _alias = name; | |
5fee5ec3 | 1422 | } |
5eb9927a IB |
1423 | else |
1424 | ob.printf("%s=%s", _alias.toChars(), name.toChars()); | |
5fee5ec3 | 1425 | } |
5eb9927a IB |
1426 | if (imp.aliasId) |
1427 | ob.printf(" -> %s", imp.aliasId.toChars()); | |
1428 | ob.writenl(); | |
5fee5ec3 IB |
1429 | } |
1430 | ||
1431 | void attribSemantic(AttribDeclaration ad) | |
1432 | { | |
235d5a96 | 1433 | if (ad.semanticRun != PASS.initial) |
5fee5ec3 IB |
1434 | return; |
1435 | ad.semanticRun = PASS.semantic; | |
1436 | Dsymbols* d = ad.include(sc); | |
1437 | //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); | |
1438 | if (d) | |
1439 | { | |
1440 | Scope* sc2 = ad.newScope(sc); | |
1441 | bool errors; | |
1442 | for (size_t i = 0; i < d.dim; i++) | |
1443 | { | |
1444 | Dsymbol s = (*d)[i]; | |
1445 | s.dsymbolSemantic(sc2); | |
1446 | errors |= s.errors; | |
1447 | } | |
1448 | ad.errors |= errors; | |
1449 | if (sc2 != sc) | |
1450 | sc2.pop(); | |
1451 | } | |
1452 | ad.semanticRun = PASS.semanticdone; | |
1453 | } | |
1454 | ||
1455 | override void visit(AttribDeclaration atd) | |
1456 | { | |
1457 | attribSemantic(atd); | |
1458 | } | |
1459 | ||
1460 | override void visit(AnonDeclaration scd) | |
1461 | { | |
9c7d5e88 | 1462 | //printf("\tAnonDeclaration::semantic isunion:%d ptr:%p\n", scd.isunion, scd); |
5fee5ec3 IB |
1463 | assert(sc.parent); |
1464 | auto p = sc.parent.pastMixin(); | |
1465 | auto ad = p.isAggregateDeclaration(); | |
1466 | if (!ad) | |
1467 | { | |
1468 | error(scd.loc, "%s can only be a part of an aggregate, not %s `%s`", scd.kind(), p.kind(), p.toChars()); | |
1469 | scd.errors = true; | |
1470 | return; | |
1471 | } | |
1472 | ||
5eb9927a IB |
1473 | if (!scd.decl) |
1474 | return; | |
1475 | ||
1476 | sc = sc.push(); | |
1477 | sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.gshared); | |
1478 | sc.inunion = scd.isunion ? scd : null; | |
1479 | sc.flags = 0; | |
1480 | for (size_t i = 0; i < scd.decl.dim; i++) | |
5fee5ec3 | 1481 | { |
5eb9927a IB |
1482 | Dsymbol s = (*scd.decl)[i]; |
1483 | if (auto var = s.isVarDeclaration) | |
5fee5ec3 | 1484 | { |
5eb9927a IB |
1485 | if (scd.isunion) |
1486 | var.overlapped = true; | |
5fee5ec3 | 1487 | } |
5eb9927a | 1488 | s.dsymbolSemantic(sc); |
5fee5ec3 | 1489 | } |
5eb9927a | 1490 | sc = sc.pop(); |
5fee5ec3 IB |
1491 | } |
1492 | ||
1493 | override void visit(PragmaDeclaration pd) | |
1494 | { | |
1495 | StringExp verifyMangleString(ref Expression e) | |
1496 | { | |
1497 | auto se = semanticString(sc, e, "mangled name"); | |
1498 | if (!se) | |
1499 | return null; | |
1500 | e = se; | |
1501 | if (!se.len) | |
1502 | { | |
1503 | pd.error("zero-length string not allowed for mangled name"); | |
1504 | return null; | |
1505 | } | |
1506 | if (se.sz != 1) | |
1507 | { | |
1508 | pd.error("mangled name characters can only be of type `char`"); | |
1509 | return null; | |
1510 | } | |
1511 | version (all) | |
1512 | { | |
1513 | /* Note: D language specification should not have any assumption about backend | |
1514 | * implementation. Ideally pragma(mangle) can accept a string of any content. | |
1515 | * | |
1516 | * Therefore, this validation is compiler implementation specific. | |
1517 | */ | |
1518 | auto slice = se.peekString(); | |
1519 | for (size_t i = 0; i < se.len;) | |
1520 | { | |
1521 | dchar c = slice[i]; | |
1522 | if (c < 0x80) | |
1523 | { | |
1524 | if (c.isValidMangling) | |
1525 | { | |
1526 | ++i; | |
1527 | continue; | |
1528 | } | |
1529 | else | |
1530 | { | |
1531 | pd.error("char 0x%02x not allowed in mangled name", c); | |
1532 | break; | |
1533 | } | |
1534 | } | |
1535 | if (const msg = utf_decodeChar(slice, i, c)) | |
1536 | { | |
1537 | pd.error("%.*s", cast(int)msg.length, msg.ptr); | |
1538 | break; | |
1539 | } | |
1540 | if (!isUniAlpha(c)) | |
1541 | { | |
1542 | pd.error("char `0x%04x` not allowed in mangled name", c); | |
1543 | break; | |
1544 | } | |
1545 | } | |
1546 | } | |
1547 | return se; | |
1548 | } | |
1549 | void declarations() | |
1550 | { | |
1551 | if (!pd.decl) | |
1552 | return; | |
1553 | ||
1554 | Scope* sc2 = pd.newScope(sc); | |
1555 | scope(exit) | |
1556 | if (sc2 != sc) | |
1557 | sc2.pop(); | |
1558 | ||
1559 | foreach (s; (*pd.decl)[]) | |
1560 | { | |
1561 | s.dsymbolSemantic(sc2); | |
1562 | if (pd.ident != Id.mangle) | |
1563 | continue; | |
1564 | assert(pd.args); | |
1565 | if (auto ad = s.isAggregateDeclaration()) | |
1566 | { | |
1567 | Expression e = (*pd.args)[0]; | |
1568 | sc2 = sc2.startCTFE(); | |
1569 | e = e.expressionSemantic(sc); | |
1570 | e = resolveProperties(sc2, e); | |
1571 | sc2 = sc2.endCTFE(); | |
1572 | AggregateDeclaration agg; | |
1573 | if (auto tc = e.type.isTypeClass()) | |
1574 | agg = tc.sym; | |
1575 | else if (auto ts = e.type.isTypeStruct()) | |
1576 | agg = ts.sym; | |
1577 | ad.mangleOverride = new MangleOverride; | |
1578 | void setString(ref Expression e) | |
1579 | { | |
1580 | if (auto se = verifyMangleString(e)) | |
1581 | { | |
1582 | const name = (cast(const(char)[])se.peekData()).xarraydup; | |
1583 | ad.mangleOverride.id = Identifier.idPool(name); | |
1584 | e = se; | |
1585 | } | |
1586 | else | |
1587 | e.error("must be a string"); | |
1588 | } | |
1589 | if (agg) | |
1590 | { | |
1591 | ad.mangleOverride.agg = agg; | |
1592 | if (pd.args.dim == 2) | |
1593 | { | |
1594 | setString((*pd.args)[1]); | |
1595 | } | |
1596 | else | |
1597 | ad.mangleOverride.id = agg.ident; | |
1598 | } | |
1599 | else | |
1600 | setString((*pd.args)[0]); | |
1601 | } | |
1602 | else if (auto td = s.isTemplateDeclaration()) | |
1603 | { | |
1604 | pd.error("cannot apply to a template declaration"); | |
1605 | errorSupplemental(pd.loc, "use `template Class(Args...){ pragma(mangle, \"other_name\") class Class {} }`"); | |
1606 | } | |
1607 | else if (auto se = verifyMangleString((*pd.args)[0])) | |
1608 | { | |
1609 | const name = (cast(const(char)[])se.peekData()).xarraydup; | |
1610 | uint cnt = setMangleOverride(s, name); | |
1611 | if (cnt > 1) | |
1612 | pd.error("can only apply to a single declaration"); | |
1613 | } | |
1614 | } | |
1615 | } | |
1616 | ||
1617 | void noDeclarations() | |
1618 | { | |
1619 | if (pd.decl) | |
1620 | { | |
1621 | pd.error("is missing a terminating `;`"); | |
1622 | declarations(); | |
1623 | // do them anyway, to avoid segfaults. | |
1624 | } | |
1625 | } | |
1626 | ||
1627 | // Should be merged with PragmaStatement | |
1628 | //printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars()); | |
d7569187 | 1629 | if (target.supportsLinkerDirective()) |
5fee5ec3 IB |
1630 | { |
1631 | if (pd.ident == Id.linkerDirective) | |
1632 | { | |
1633 | if (!pd.args || pd.args.dim != 1) | |
1634 | pd.error("one string argument expected for pragma(linkerDirective)"); | |
1635 | else | |
1636 | { | |
1637 | auto se = semanticString(sc, (*pd.args)[0], "linker directive"); | |
1638 | if (!se) | |
1639 | return noDeclarations(); | |
1640 | (*pd.args)[0] = se; | |
1641 | if (global.params.verbose) | |
1642 | message("linkopt %.*s", cast(int)se.len, se.peekString().ptr); | |
1643 | } | |
1644 | return noDeclarations(); | |
1645 | } | |
1646 | } | |
1647 | if (pd.ident == Id.msg) | |
1648 | { | |
5eb9927a IB |
1649 | if (!pd.args) |
1650 | return noDeclarations(); | |
1651 | ||
1652 | for (size_t i = 0; i < pd.args.dim; i++) | |
5fee5ec3 | 1653 | { |
5eb9927a IB |
1654 | Expression e = (*pd.args)[i]; |
1655 | sc = sc.startCTFE(); | |
1656 | e = e.expressionSemantic(sc); | |
1657 | e = resolveProperties(sc, e); | |
1658 | sc = sc.endCTFE(); | |
1659 | e = ctfeInterpretForPragmaMsg(e); | |
1660 | if (e.op == EXP.error) | |
5fee5ec3 | 1661 | { |
5eb9927a IB |
1662 | errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars()); |
1663 | return; | |
5fee5ec3 | 1664 | } |
5eb9927a IB |
1665 | StringExp se = e.toStringExp(); |
1666 | if (se) | |
1667 | { | |
1668 | se = se.toUTF8(sc); | |
1669 | fprintf(stderr, "%.*s", cast(int)se.len, se.peekString().ptr); | |
1670 | } | |
1671 | else | |
1672 | fprintf(stderr, "%s", e.toChars()); | |
5fee5ec3 | 1673 | } |
5eb9927a IB |
1674 | fprintf(stderr, "\n"); |
1675 | ||
5fee5ec3 IB |
1676 | return noDeclarations(); |
1677 | } | |
1678 | else if (pd.ident == Id.lib) | |
1679 | { | |
1680 | if (!pd.args || pd.args.dim != 1) | |
1681 | pd.error("string expected for library name"); | |
1682 | else | |
1683 | { | |
1684 | auto se = semanticString(sc, (*pd.args)[0], "library name"); | |
1685 | if (!se) | |
1686 | return noDeclarations(); | |
1687 | (*pd.args)[0] = se; | |
1688 | ||
1689 | auto name = se.peekString().xarraydup; | |
1690 | if (global.params.verbose) | |
1691 | message("library %s", name.ptr); | |
5eb9927a | 1692 | if (global.params.moduleDeps.buffer && !global.params.moduleDeps.name) |
5fee5ec3 | 1693 | { |
5eb9927a | 1694 | OutBuffer* ob = global.params.moduleDeps.buffer; |
5fee5ec3 IB |
1695 | Module imod = sc._module; |
1696 | ob.writestring("depsLib "); | |
1697 | ob.writestring(imod.toPrettyChars()); | |
1698 | ob.writestring(" ("); | |
1699 | escapePath(ob, imod.srcfile.toChars()); | |
1700 | ob.writestring(") : "); | |
1701 | ob.writestring(name); | |
1702 | ob.writenl(); | |
1703 | } | |
1704 | mem.xfree(name.ptr); | |
1705 | } | |
1706 | return noDeclarations(); | |
1707 | } | |
1708 | else if (pd.ident == Id.startaddress) | |
1709 | { | |
1710 | if (!pd.args || pd.args.dim != 1) | |
1711 | pd.error("function name expected for start address"); | |
1712 | else | |
1713 | { | |
1714 | /* https://issues.dlang.org/show_bug.cgi?id=11980 | |
1715 | * resolveProperties and ctfeInterpret call are not necessary. | |
1716 | */ | |
1717 | Expression e = (*pd.args)[0]; | |
1718 | sc = sc.startCTFE(); | |
1719 | e = e.expressionSemantic(sc); | |
1720 | sc = sc.endCTFE(); | |
1721 | (*pd.args)[0] = e; | |
1722 | Dsymbol sa = getDsymbol(e); | |
1723 | if (!sa || !sa.isFuncDeclaration()) | |
1724 | pd.error("function name expected for start address, not `%s`", e.toChars()); | |
1725 | } | |
1726 | return noDeclarations(); | |
1727 | } | |
1728 | else if (pd.ident == Id.Pinline) | |
1729 | { | |
1730 | if (pd.args && pd.args.dim > 1) | |
1731 | { | |
1732 | pd.error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) pd.args.dim); | |
1733 | pd.args.setDim(1); | |
1734 | (*pd.args)[0] = ErrorExp.get(); | |
1735 | } | |
1736 | ||
1737 | // this pragma now gets evaluated on demand in function semantic | |
1738 | ||
1739 | return declarations(); | |
1740 | } | |
1741 | else if (pd.ident == Id.mangle) | |
1742 | { | |
1743 | if (!pd.args) | |
1744 | pd.args = new Expressions(); | |
1745 | if (pd.args.dim == 0 || pd.args.dim > 2) | |
1746 | { | |
1747 | pd.error(pd.args.dim == 0 ? "string expected for mangled name" | |
1748 | : "expected 1 or 2 arguments"); | |
1749 | pd.args.setDim(1); | |
1750 | (*pd.args)[0] = ErrorExp.get(); // error recovery | |
1751 | } | |
1752 | return declarations(); | |
1753 | } | |
1754 | else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) | |
1755 | { | |
1756 | if (pd.args && pd.args.dim != 0) | |
1757 | pd.error("takes no argument"); | |
0fb57034 IB |
1758 | else |
1759 | { | |
1760 | immutable isCtor = pd.ident == Id.crt_constructor; | |
1761 | ||
1762 | static uint recurse(Dsymbol s, bool isCtor) | |
1763 | { | |
1764 | if (auto ad = s.isAttribDeclaration()) | |
1765 | { | |
1766 | uint nestedCount; | |
1767 | auto decls = ad.include(null); | |
1768 | if (decls) | |
1769 | { | |
1770 | for (size_t i = 0; i < decls.dim; ++i) | |
1771 | nestedCount += recurse((*decls)[i], isCtor); | |
1772 | } | |
1773 | return nestedCount; | |
1774 | } | |
1775 | else if (auto f = s.isFuncDeclaration()) | |
1776 | { | |
235d5a96 | 1777 | f.flags |= isCtor ? FUNCFLAG.CRTCtor : FUNCFLAG.CRTDtor; |
0fb57034 IB |
1778 | return 1; |
1779 | } | |
1780 | else | |
1781 | return 0; | |
1782 | assert(0); | |
1783 | } | |
1784 | ||
1785 | if (recurse(pd, isCtor) > 1) | |
1786 | pd.error("can only apply to a single declaration"); | |
1787 | } | |
5fee5ec3 IB |
1788 | return declarations(); |
1789 | } | |
1790 | else if (pd.ident == Id.printf || pd.ident == Id.scanf) | |
1791 | { | |
1792 | if (pd.args && pd.args.dim != 0) | |
1793 | pd.error("takes no argument"); | |
1794 | return declarations(); | |
1795 | } | |
1796 | else if (!global.params.ignoreUnsupportedPragmas) | |
1797 | { | |
1798 | error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars()); | |
1799 | return declarations(); | |
1800 | } | |
1801 | ||
1802 | if (!global.params.verbose) | |
1803 | return declarations(); | |
1804 | ||
1805 | /* Print unrecognized pragmas | |
1806 | */ | |
1807 | OutBuffer buf; | |
1808 | buf.writestring(pd.ident.toString()); | |
1809 | if (pd.args) | |
1810 | { | |
1811 | const errors_save = global.startGagging(); | |
1812 | for (size_t i = 0; i < pd.args.dim; i++) | |
1813 | { | |
1814 | Expression e = (*pd.args)[i]; | |
1815 | sc = sc.startCTFE(); | |
1816 | e = e.expressionSemantic(sc); | |
1817 | e = resolveProperties(sc, e); | |
1818 | sc = sc.endCTFE(); | |
1819 | e = e.ctfeInterpret(); | |
1820 | if (i == 0) | |
1821 | buf.writestring(" ("); | |
1822 | else | |
1823 | buf.writeByte(','); | |
1824 | buf.writestring(e.toChars()); | |
1825 | } | |
1826 | if (pd.args.dim) | |
1827 | buf.writeByte(')'); | |
1828 | global.endGagging(errors_save); | |
1829 | } | |
1830 | message("pragma %s", buf.peekChars()); | |
1831 | return declarations(); | |
1832 | } | |
1833 | ||
1834 | override void visit(StaticIfDeclaration sid) | |
1835 | { | |
1836 | attribSemantic(sid); | |
1837 | } | |
1838 | ||
1839 | override void visit(StaticForeachDeclaration sfd) | |
1840 | { | |
1841 | attribSemantic(sfd); | |
1842 | } | |
1843 | ||
1844 | private Dsymbols* compileIt(CompileDeclaration cd) | |
1845 | { | |
1846 | //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars()); | |
1847 | OutBuffer buf; | |
1848 | if (expressionsToString(buf, sc, cd.exps)) | |
1849 | return null; | |
1850 | ||
1851 | const errors = global.errors; | |
1852 | const len = buf.length; | |
1853 | buf.writeByte(0); | |
1854 | const str = buf.extractSlice()[0 .. len]; | |
1855 | scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false); | |
1856 | p.nextToken(); | |
1857 | ||
1858 | auto d = p.parseDeclDefs(0); | |
1859 | if (global.errors != errors) | |
1860 | return null; | |
1861 | ||
1862 | if (p.token.value != TOK.endOfFile) | |
1863 | { | |
1864 | cd.error("incomplete mixin declaration `%s`", str.ptr); | |
1865 | return null; | |
1866 | } | |
1867 | return d; | |
1868 | } | |
1869 | ||
1870 | /*********************************************************** | |
1871 | * https://dlang.org/spec/module.html#mixin-declaration | |
1872 | */ | |
1873 | override void visit(CompileDeclaration cd) | |
1874 | { | |
1875 | //printf("CompileDeclaration::semantic()\n"); | |
1876 | if (!cd.compiled) | |
1877 | { | |
1878 | cd.decl = compileIt(cd); | |
1879 | cd.AttribDeclaration.addMember(sc, cd.scopesym); | |
1880 | cd.compiled = true; | |
1881 | ||
1882 | if (cd._scope && cd.decl) | |
1883 | { | |
1884 | for (size_t i = 0; i < cd.decl.dim; i++) | |
1885 | { | |
1886 | Dsymbol s = (*cd.decl)[i]; | |
1887 | s.setScope(cd._scope); | |
1888 | } | |
1889 | } | |
1890 | } | |
1891 | attribSemantic(cd); | |
1892 | } | |
1893 | ||
1894 | override void visit(CPPNamespaceDeclaration ns) | |
1895 | { | |
1896 | Identifier identFromSE (StringExp se) | |
1897 | { | |
1898 | const sident = se.toStringz(); | |
1899 | if (!sident.length || !Identifier.isValidIdentifier(sident)) | |
1900 | { | |
1901 | ns.exp.error("expected valid identifier for C++ namespace but got `%.*s`", | |
1902 | cast(int)sident.length, sident.ptr); | |
1903 | return null; | |
1904 | } | |
1905 | else | |
1906 | return Identifier.idPool(sident); | |
1907 | } | |
1908 | ||
5eb9927a IB |
1909 | if (ns.ident !is null) |
1910 | return attribSemantic(ns); | |
1911 | ||
1912 | ns.cppnamespace = sc.namespace; | |
1913 | sc = sc.startCTFE(); | |
1914 | ns.exp = ns.exp.expressionSemantic(sc); | |
1915 | ns.exp = resolveProperties(sc, ns.exp); | |
1916 | sc = sc.endCTFE(); | |
1917 | ns.exp = ns.exp.ctfeInterpret(); | |
1918 | // Can be either a tuple of strings or a string itself | |
1919 | if (auto te = ns.exp.isTupleExp()) | |
1920 | { | |
1921 | expandTuples(te.exps); | |
1922 | CPPNamespaceDeclaration current = ns.cppnamespace; | |
1923 | for (size_t d = 0; d < te.exps.dim; ++d) | |
1924 | { | |
1925 | auto exp = (*te.exps)[d]; | |
1926 | auto prev = d ? current : ns.cppnamespace; | |
1927 | current = (d + 1) != te.exps.dim | |
1928 | ? new CPPNamespaceDeclaration(ns.loc, exp, null) | |
1929 | : ns; | |
1930 | current.exp = exp; | |
1931 | current.cppnamespace = prev; | |
1932 | if (auto se = exp.toStringExp()) | |
5fee5ec3 | 1933 | { |
5eb9927a IB |
1934 | current.ident = identFromSE(se); |
1935 | if (current.ident is null) | |
1936 | return; // An error happened in `identFromSE` | |
5fee5ec3 | 1937 | } |
5eb9927a IB |
1938 | else |
1939 | ns.exp.error("`%s`: index %llu is not a string constant, it is a `%s`", | |
1940 | ns.exp.toChars(), cast(ulong) d, ns.exp.type.toChars()); | |
5fee5ec3 | 1941 | } |
5fee5ec3 | 1942 | } |
5eb9927a IB |
1943 | else if (auto se = ns.exp.toStringExp()) |
1944 | ns.ident = identFromSE(se); | |
1945 | // Empty Tuple | |
1946 | else if (ns.exp.isTypeExp() && ns.exp.isTypeExp().type.toBasetype().isTypeTuple()) | |
1947 | { | |
1948 | } | |
1949 | else | |
1950 | ns.exp.error("compile time string constant (or tuple) expected, not `%s`", | |
1951 | ns.exp.toChars()); | |
5fee5ec3 IB |
1952 | attribSemantic(ns); |
1953 | } | |
1954 | ||
1955 | override void visit(UserAttributeDeclaration uad) | |
1956 | { | |
1957 | //printf("UserAttributeDeclaration::semantic() %p\n", this); | |
1958 | if (uad.decl && !uad._scope) | |
1959 | uad.Dsymbol.setScope(sc); // for function local symbols | |
c8dfa79c | 1960 | arrayExpressionSemantic(uad.atts.peekSlice(), sc, true); |
5fee5ec3 IB |
1961 | return attribSemantic(uad); |
1962 | } | |
1963 | ||
1964 | override void visit(StaticAssert sa) | |
1965 | { | |
1966 | if (sa.semanticRun < PASS.semanticdone) | |
1967 | sa.semanticRun = PASS.semanticdone; | |
1968 | } | |
1969 | ||
1970 | override void visit(DebugSymbol ds) | |
1971 | { | |
1972 | //printf("DebugSymbol::semantic() %s\n", toChars()); | |
1973 | if (ds.semanticRun < PASS.semanticdone) | |
1974 | ds.semanticRun = PASS.semanticdone; | |
1975 | } | |
1976 | ||
1977 | override void visit(VersionSymbol vs) | |
1978 | { | |
1979 | if (vs.semanticRun < PASS.semanticdone) | |
1980 | vs.semanticRun = PASS.semanticdone; | |
1981 | } | |
1982 | ||
1983 | override void visit(Package pkg) | |
1984 | { | |
1985 | if (pkg.semanticRun < PASS.semanticdone) | |
1986 | pkg.semanticRun = PASS.semanticdone; | |
1987 | } | |
1988 | ||
1989 | override void visit(Module m) | |
1990 | { | |
235d5a96 | 1991 | if (m.semanticRun != PASS.initial) |
5fee5ec3 IB |
1992 | return; |
1993 | //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); | |
1994 | m.semanticRun = PASS.semantic; | |
1995 | // Note that modules get their own scope, from scratch. | |
1996 | // This is so regardless of where in the syntax a module | |
1997 | // gets imported, it is unaffected by context. | |
1998 | Scope* sc = m._scope; // see if already got one from importAll() | |
1999 | if (!sc) | |
2000 | { | |
2001 | sc = Scope.createGlobal(m); // create root scope | |
2002 | } | |
2003 | ||
2004 | //printf("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage); | |
2005 | // Pass 1 semantic routines: do public side of the definition | |
2006 | m.members.foreachDsymbol( (s) | |
2007 | { | |
2008 | //printf("\tModule('%s'): '%s'.dsymbolSemantic()\n", toChars(), s.toChars()); | |
2009 | s.dsymbolSemantic(sc); | |
2010 | m.runDeferredSemantic(); | |
2011 | }); | |
2012 | ||
2013 | if (m.userAttribDecl) | |
2014 | { | |
2015 | m.userAttribDecl.dsymbolSemantic(sc); | |
2016 | } | |
2017 | if (!m._scope) | |
2018 | { | |
2019 | sc = sc.pop(); | |
2020 | sc.pop(); // 2 pops because Scope.createGlobal() created 2 | |
2021 | } | |
2022 | m.semanticRun = PASS.semanticdone; | |
2023 | //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); | |
2024 | } | |
2025 | ||
2026 | override void visit(EnumDeclaration ed) | |
2027 | { | |
2028 | //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); | |
b6df1132 | 2029 | //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); |
5fee5ec3 IB |
2030 | if (ed.semanticRun >= PASS.semanticdone) |
2031 | return; // semantic() already completed | |
2032 | if (ed.semanticRun == PASS.semantic) | |
2033 | { | |
2034 | assert(ed.memtype); | |
2035 | error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); | |
2036 | ed.errors = true; | |
2037 | ed.semanticRun = PASS.semanticdone; | |
2038 | return; | |
2039 | } | |
5fee5ec3 IB |
2040 | Scope* scx = null; |
2041 | if (ed._scope) | |
2042 | { | |
2043 | sc = ed._scope; | |
2044 | scx = ed._scope; // save so we don't make redundant copies | |
2045 | ed._scope = null; | |
2046 | } | |
2047 | ||
2048 | if (!sc) | |
2049 | return; | |
2050 | ||
2051 | ed.parent = sc.parent; | |
2052 | ed.type = ed.type.typeSemantic(ed.loc, sc); | |
2053 | ||
2054 | ed.visibility = sc.visibility; | |
2055 | if (sc.stc & STC.deprecated_) | |
2056 | ed.isdeprecated = true; | |
2057 | ed.userAttribDecl = sc.userAttribDecl; | |
2058 | ed.cppnamespace = sc.namespace; | |
2059 | ||
2060 | ed.semanticRun = PASS.semantic; | |
2061 | UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); | |
31350635 | 2062 | checkMustUseReserved(ed); |
5fee5ec3 IB |
2063 | |
2064 | if (!ed.members && !ed.memtype) // enum ident; | |
2065 | { | |
2066 | ed.semanticRun = PASS.semanticdone; | |
2067 | return; | |
2068 | } | |
2069 | ||
2070 | if (!ed.symtab) | |
2071 | ed.symtab = new DsymbolTable(); | |
2072 | ||
2073 | /* The separate, and distinct, cases are: | |
2074 | * 1. enum { ... } | |
2075 | * 2. enum : memtype { ... } | |
2076 | * 3. enum ident { ... } | |
2077 | * 4. enum ident : memtype { ... } | |
2078 | * 5. enum ident : memtype; | |
2079 | * 6. enum ident; | |
2080 | */ | |
2081 | ||
2082 | if (ed.memtype) | |
2083 | { | |
2084 | ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); | |
2085 | ||
2086 | /* Check to see if memtype is forward referenced | |
2087 | */ | |
2088 | if (auto te = ed.memtype.isTypeEnum()) | |
2089 | { | |
2090 | auto sym = te.toDsymbol(sc).isEnumDeclaration(); | |
2091 | // Special enums like __c_[u]long[long] are fine to forward reference | |
2092 | // see https://issues.dlang.org/show_bug.cgi?id=20599 | |
2093 | if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope)) | |
2094 | { | |
2095 | // memtype is forward referenced, so try again later | |
2096 | deferDsymbolSemantic(ed, scx); | |
5fee5ec3 | 2097 | //printf("\tdeferring %s\n", toChars()); |
235d5a96 | 2098 | ed.semanticRun = PASS.initial; |
5fee5ec3 IB |
2099 | return; |
2100 | } | |
2101 | else | |
2102 | // Ensure that semantic is run to detect. e.g. invalid forward references | |
2103 | sym.dsymbolSemantic(sc); | |
2104 | } | |
2105 | if (ed.memtype.ty == Tvoid) | |
2106 | { | |
2107 | ed.error("base type must not be `void`"); | |
2108 | ed.memtype = Type.terror; | |
2109 | } | |
2110 | if (ed.memtype.ty == Terror) | |
2111 | { | |
2112 | ed.errors = true; | |
2113 | // poison all the members | |
2114 | ed.members.foreachDsymbol( (s) { s.errors = true; } ); | |
2115 | ed.semanticRun = PASS.semanticdone; | |
2116 | return; | |
2117 | } | |
2118 | } | |
2119 | ||
2120 | if (!ed.members) // enum ident : memtype; | |
2121 | { | |
2122 | ed.semanticRun = PASS.semanticdone; | |
2123 | return; | |
2124 | } | |
2125 | ||
2126 | if (ed.members.dim == 0) | |
2127 | { | |
2128 | ed.error("enum `%s` must have at least one member", ed.toChars()); | |
2129 | ed.errors = true; | |
2130 | ed.semanticRun = PASS.semanticdone; | |
2131 | return; | |
2132 | } | |
2133 | ||
2134 | if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done | |
2135 | ed.semanticRun = PASS.semanticdone; | |
2136 | ||
7e287503 IB |
2137 | // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint |
2138 | // Deprecated in 2.100 | |
2139 | // Make an error in 2.110 | |
2140 | if (sc.stc & STC.scope_) | |
2141 | deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); | |
2142 | ||
5fee5ec3 IB |
2143 | Scope* sce; |
2144 | if (ed.isAnonymous()) | |
2145 | sce = sc; | |
2146 | else | |
2147 | { | |
2148 | sce = sc.push(ed); | |
2149 | sce.parent = ed; | |
2150 | } | |
2151 | sce = sce.startCTFE(); | |
2152 | sce.setNoFree(); // needed for getMaxMinValue() | |
2153 | ||
2154 | /* Each enum member gets the sce scope | |
2155 | */ | |
2156 | ed.members.foreachDsymbol( (s) | |
2157 | { | |
2158 | EnumMember em = s.isEnumMember(); | |
2159 | if (em) | |
2160 | em._scope = sce; | |
2161 | }); | |
2162 | ||
2163 | /* addMember() is not called when the EnumDeclaration appears as a function statement, | |
2164 | * so we have to do what addMember() does and install the enum members in the right symbol | |
2165 | * table | |
2166 | */ | |
2167 | addEnumMembers(ed, sc, sc.getScopesym()); | |
2168 | ||
2169 | if (sc.flags & SCOPE.Cfile) | |
2170 | { | |
2171 | /* C11 6.7.2.2 | |
2172 | */ | |
d7569187 | 2173 | assert(ed.memtype); |
5fee5ec3 IB |
2174 | int nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 |
2175 | ||
445d8def IB |
2176 | // C11 6.7.2.2-2 value must be representable as an int. |
2177 | // The sizemask represents all values that int will fit into, | |
2178 | // from 0..uint.max. We want to cover int.min..uint.max. | |
2179 | const mask = Type.tint32.sizemask(); | |
2180 | IntRange ir = IntRange(SignExtendedNumber(~(mask >> 1), true), | |
2181 | SignExtendedNumber(mask)); | |
2182 | ||
5fee5ec3 IB |
2183 | void emSemantic(EnumMember em, ref int nextValue) |
2184 | { | |
2185 | static void errorReturn(EnumMember em) | |
2186 | { | |
2187 | em.errors = true; | |
2188 | em.semanticRun = PASS.semanticdone; | |
2189 | } | |
2190 | ||
2191 | em.semanticRun = PASS.semantic; | |
2192 | em.type = Type.tint32; | |
5eb9927a | 2193 | em._linkage = LINK.c; |
5fee5ec3 IB |
2194 | em.storage_class |= STC.manifest; |
2195 | if (em.value) | |
2196 | { | |
2197 | Expression e = em.value; | |
2198 | assert(e.dyncast() == DYNCAST.expression); | |
2199 | e = e.expressionSemantic(sc); | |
2200 | e = resolveProperties(sc, e); | |
2201 | e = e.integralPromotions(sc); | |
2202 | e = e.ctfeInterpret(); | |
9c7d5e88 | 2203 | if (e.op == EXP.error) |
5fee5ec3 IB |
2204 | return errorReturn(em); |
2205 | auto ie = e.isIntegerExp(); | |
2206 | if (!ie) | |
2207 | { | |
2208 | // C11 6.7.2.2-2 | |
2209 | em.error("enum member must be an integral constant expression, not `%s` of type `%s`", e.toChars(), e.type.toChars()); | |
2210 | return errorReturn(em); | |
2211 | } | |
445d8def | 2212 | if (!ir.contains(getIntRange(ie))) |
5fee5ec3 IB |
2213 | { |
2214 | // C11 6.7.2.2-2 | |
2215 | em.error("enum member value `%s` does not fit in an `int`", e.toChars()); | |
2216 | return errorReturn(em); | |
2217 | } | |
445d8def IB |
2218 | nextValue = cast(int)ie.toInteger(); |
2219 | em.value = new IntegerExp(em.loc, nextValue, Type.tint32); | |
5fee5ec3 IB |
2220 | } |
2221 | else | |
2222 | { | |
445d8def IB |
2223 | // C11 6.7.2.2-3 add 1 to value of previous enumeration constant |
2224 | bool first = (em == (*em.ed.members)[0]); | |
2225 | if (!first) | |
2226 | { | |
2227 | import core.checkedint : adds; | |
2228 | bool overflow; | |
2229 | nextValue = adds(nextValue, 1, overflow); | |
2230 | if (overflow) | |
2231 | { | |
2232 | em.error("initialization with `%d+1` causes overflow for type `int`", nextValue - 1); | |
2233 | return errorReturn(em); | |
2234 | } | |
2235 | } | |
5fee5ec3 IB |
2236 | em.value = new IntegerExp(em.loc, nextValue, Type.tint32); |
2237 | } | |
5fee5ec3 IB |
2238 | em.semanticRun = PASS.semanticdone; |
2239 | } | |
2240 | ||
2241 | ed.members.foreachDsymbol( (s) | |
2242 | { | |
2243 | if (EnumMember em = s.isEnumMember()) | |
2244 | emSemantic(em, nextValue); | |
2245 | }); | |
2246 | ed.semanticRun = PASS.semanticdone; | |
2247 | return; | |
2248 | } | |
2249 | ||
2250 | ed.members.foreachDsymbol( (s) | |
2251 | { | |
2252 | if (EnumMember em = s.isEnumMember()) | |
2253 | em.dsymbolSemantic(em._scope); | |
2254 | }); | |
2255 | //printf("defaultval = %lld\n", defaultval); | |
2256 | ||
2257 | //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars()); | |
2258 | //printf("members = %s\n", members.toChars()); | |
2259 | } | |
2260 | ||
2261 | override void visit(EnumMember em) | |
2262 | { | |
2263 | //printf("EnumMember::semantic() %s\n", em.toChars()); | |
2264 | ||
2265 | void errorReturn() | |
2266 | { | |
2267 | em.errors = true; | |
2268 | em.semanticRun = PASS.semanticdone; | |
2269 | } | |
2270 | ||
2271 | if (em.errors || em.semanticRun >= PASS.semanticdone) | |
2272 | return; | |
2273 | if (em.semanticRun == PASS.semantic) | |
2274 | { | |
2275 | em.error("circular reference to `enum` member"); | |
2276 | return errorReturn(); | |
2277 | } | |
2278 | assert(em.ed); | |
2279 | ||
2280 | em.ed.dsymbolSemantic(sc); | |
2281 | if (em.ed.errors) | |
2282 | return errorReturn(); | |
2283 | if (em.errors || em.semanticRun >= PASS.semanticdone) | |
2284 | return; | |
2285 | ||
2286 | if (em._scope) | |
2287 | sc = em._scope; | |
2288 | if (!sc) | |
2289 | return; | |
2290 | ||
2291 | em.semanticRun = PASS.semantic; | |
2292 | ||
2293 | em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); | |
5eb9927a | 2294 | em._linkage = LINK.d; |
5fee5ec3 IB |
2295 | em.storage_class |= STC.manifest; |
2296 | ||
2297 | // https://issues.dlang.org/show_bug.cgi?id=9701 | |
2298 | if (em.ed.isAnonymous()) | |
2299 | { | |
2300 | if (em.userAttribDecl) | |
2301 | em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; | |
2302 | else | |
2303 | em.userAttribDecl = em.ed.userAttribDecl; | |
2304 | } | |
2305 | ||
2306 | // Eval UDA in this same scope. Issues 19344, 20835, 21122 | |
2307 | if (em.userAttribDecl) | |
2308 | { | |
2309 | // Set scope but avoid extra sc.uda attachment inside setScope() | |
2310 | auto inneruda = em.userAttribDecl.userAttribDecl; | |
2311 | em.userAttribDecl.setScope(sc); | |
2312 | em.userAttribDecl.userAttribDecl = inneruda; | |
2313 | } | |
2314 | ||
2315 | // The first enum member is special | |
2316 | bool first = (em == (*em.ed.members)[0]); | |
2317 | ||
2318 | if (em.origType) | |
2319 | { | |
2320 | em.origType = em.origType.typeSemantic(em.loc, sc); | |
2321 | em.type = em.origType; | |
2322 | assert(em.value); // "type id;" is not a valid enum member declaration | |
2323 | } | |
2324 | ||
2325 | if (em.value) | |
2326 | { | |
2327 | Expression e = em.value; | |
2328 | assert(e.dyncast() == DYNCAST.expression); | |
2329 | e = e.expressionSemantic(sc); | |
2330 | e = resolveProperties(sc, e); | |
2331 | e = e.ctfeInterpret(); | |
9c7d5e88 | 2332 | if (e.op == EXP.error) |
5fee5ec3 IB |
2333 | return errorReturn(); |
2334 | if (first && !em.ed.memtype && !em.ed.isAnonymous()) | |
2335 | { | |
2336 | em.ed.memtype = e.type; | |
2337 | if (em.ed.memtype.ty == Terror) | |
2338 | { | |
2339 | em.ed.errors = true; | |
2340 | return errorReturn(); | |
2341 | } | |
2342 | if (em.ed.memtype.ty != Terror) | |
2343 | { | |
2344 | /* https://issues.dlang.org/show_bug.cgi?id=11746 | |
2345 | * All of named enum members should have same type | |
2346 | * with the first member. If the following members were referenced | |
2347 | * during the first member semantic, their types should be unified. | |
2348 | */ | |
2349 | em.ed.members.foreachDsymbol( (s) | |
2350 | { | |
2351 | EnumMember enm = s.isEnumMember(); | |
2352 | if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) | |
2353 | return; | |
2354 | ||
2355 | //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); | |
2356 | Expression ev = enm.value; | |
2357 | ev = ev.implicitCastTo(sc, em.ed.memtype); | |
2358 | ev = ev.ctfeInterpret(); | |
2359 | ev = ev.castTo(sc, em.ed.type); | |
9c7d5e88 | 2360 | if (ev.op == EXP.error) |
5fee5ec3 IB |
2361 | em.ed.errors = true; |
2362 | enm.value = ev; | |
2363 | }); | |
2364 | ||
2365 | if (em.ed.errors) | |
2366 | { | |
2367 | em.ed.memtype = Type.terror; | |
2368 | return errorReturn(); | |
2369 | } | |
2370 | } | |
2371 | } | |
2372 | ||
2373 | if (em.ed.memtype && !em.origType) | |
2374 | { | |
2375 | e = e.implicitCastTo(sc, em.ed.memtype); | |
2376 | e = e.ctfeInterpret(); | |
2377 | ||
2378 | // save origValue for better json output | |
2379 | em.origValue = e; | |
2380 | ||
2381 | if (!em.ed.isAnonymous()) | |
2382 | { | |
2383 | e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 | |
2384 | e = e.ctfeInterpret(); | |
2385 | } | |
2386 | } | |
2387 | else if (em.origType) | |
2388 | { | |
2389 | e = e.implicitCastTo(sc, em.origType); | |
2390 | e = e.ctfeInterpret(); | |
2391 | assert(em.ed.isAnonymous()); | |
2392 | ||
2393 | // save origValue for better json output | |
2394 | em.origValue = e; | |
2395 | } | |
2396 | em.value = e; | |
2397 | } | |
2398 | else if (first) | |
2399 | { | |
2400 | Type t; | |
2401 | if (em.ed.memtype) | |
2402 | t = em.ed.memtype; | |
2403 | else | |
2404 | { | |
2405 | t = Type.tint32; | |
2406 | if (!em.ed.isAnonymous()) | |
2407 | em.ed.memtype = t; | |
2408 | } | |
2409 | Expression e = new IntegerExp(em.loc, 0, t); | |
2410 | e = e.ctfeInterpret(); | |
2411 | ||
2412 | // save origValue for better json output | |
2413 | em.origValue = e; | |
2414 | ||
2415 | if (!em.ed.isAnonymous()) | |
2416 | { | |
2417 | e = e.castTo(sc, em.ed.type); | |
2418 | e = e.ctfeInterpret(); | |
2419 | } | |
2420 | em.value = e; | |
2421 | } | |
2422 | else | |
2423 | { | |
2424 | /* Find the previous enum member, | |
2425 | * and set this to be the previous value + 1 | |
2426 | */ | |
2427 | EnumMember emprev = null; | |
2428 | em.ed.members.foreachDsymbol( (s) | |
2429 | { | |
2430 | if (auto enm = s.isEnumMember()) | |
2431 | { | |
2432 | if (enm == em) | |
2433 | return 1; // found | |
2434 | emprev = enm; | |
2435 | } | |
2436 | return 0; // continue | |
2437 | }); | |
2438 | ||
2439 | assert(emprev); | |
2440 | if (emprev.semanticRun < PASS.semanticdone) // if forward reference | |
2441 | emprev.dsymbolSemantic(emprev._scope); // resolve it | |
2442 | if (emprev.errors) | |
2443 | return errorReturn(); | |
2444 | ||
2445 | Expression eprev = emprev.value; | |
2446 | // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 | |
2447 | Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) | |
2448 | ? em.ed.memtype | |
2449 | : eprev.type; | |
6384eff5 IB |
2450 | /* |
2451 | https://issues.dlang.org/show_bug.cgi?id=20777 | |
2452 | Previously this used getProperty, which doesn't consider anything user defined, | |
2453 | this construct does do that and thus fixes the bug. | |
2454 | */ | |
2455 | Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); | |
5fee5ec3 IB |
2456 | emax = emax.expressionSemantic(sc); |
2457 | emax = emax.ctfeInterpret(); | |
2458 | ||
2459 | // Set value to (eprev + 1). | |
2460 | // But first check that (eprev != emax) | |
2461 | assert(eprev); | |
9c7d5e88 | 2462 | Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); |
5fee5ec3 IB |
2463 | e = e.expressionSemantic(sc); |
2464 | e = e.ctfeInterpret(); | |
2465 | if (e.toInteger()) | |
2466 | { | |
2467 | em.error("initialization with `%s.%s+1` causes overflow for type `%s`", | |
2468 | emprev.ed.toChars(), emprev.toChars(), em.ed.memtype.toChars()); | |
2469 | return errorReturn(); | |
2470 | } | |
2471 | ||
2472 | // Now set e to (eprev + 1) | |
2473 | e = new AddExp(em.loc, eprev, IntegerExp.literal!1); | |
2474 | e = e.expressionSemantic(sc); | |
2475 | e = e.castTo(sc, eprev.type); | |
2476 | e = e.ctfeInterpret(); | |
2477 | ||
2478 | // save origValue (without cast) for better json output | |
9c7d5e88 | 2479 | if (e.op != EXP.error) // avoid duplicate diagnostics |
5fee5ec3 IB |
2480 | { |
2481 | assert(emprev.origValue); | |
2482 | em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); | |
2483 | em.origValue = em.origValue.expressionSemantic(sc); | |
2484 | em.origValue = em.origValue.ctfeInterpret(); | |
2485 | } | |
2486 | ||
9c7d5e88 | 2487 | if (e.op == EXP.error) |
5fee5ec3 IB |
2488 | return errorReturn(); |
2489 | if (e.type.isfloating()) | |
2490 | { | |
2491 | // Check that e != eprev (not always true for floats) | |
9c7d5e88 | 2492 | Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); |
5fee5ec3 IB |
2493 | etest = etest.expressionSemantic(sc); |
2494 | etest = etest.ctfeInterpret(); | |
2495 | if (etest.toInteger()) | |
2496 | { | |
2497 | em.error("has inexact value due to loss of precision"); | |
2498 | return errorReturn(); | |
2499 | } | |
2500 | } | |
2501 | em.value = e; | |
2502 | } | |
2503 | if (!em.origType) | |
2504 | em.type = em.value.type; | |
2505 | ||
2506 | assert(em.origValue); | |
2507 | em.semanticRun = PASS.semanticdone; | |
2508 | } | |
2509 | ||
2510 | override void visit(TemplateDeclaration tempdecl) | |
2511 | { | |
2512 | static if (LOG) | |
2513 | { | |
2514 | printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars()); | |
2515 | printf("sc.stc = %llx\n", sc.stc); | |
2516 | printf("sc.module = %s\n", sc._module.toChars()); | |
2517 | } | |
235d5a96 | 2518 | if (tempdecl.semanticRun != PASS.initial) |
5fee5ec3 IB |
2519 | return; // semantic() already run |
2520 | ||
2521 | if (tempdecl._scope) | |
2522 | { | |
2523 | sc = tempdecl._scope; | |
2524 | tempdecl._scope = null; | |
2525 | } | |
2526 | if (!sc) | |
2527 | return; | |
2528 | ||
2529 | // Remember templates defined in module object that we need to know about | |
2530 | if (sc._module && sc._module.ident == Id.object) | |
2531 | { | |
2532 | if (tempdecl.ident == Id.RTInfo) | |
2533 | Type.rtinfo = tempdecl; | |
2534 | } | |
2535 | ||
2536 | /* Remember Scope for later instantiations, but make | |
2537 | * a copy since attributes can change. | |
2538 | */ | |
2539 | if (!tempdecl._scope) | |
2540 | { | |
2541 | tempdecl._scope = sc.copy(); | |
2542 | tempdecl._scope.setNoFree(); | |
2543 | } | |
2544 | ||
2545 | tempdecl.semanticRun = PASS.semantic; | |
2546 | ||
2547 | tempdecl.parent = sc.parent; | |
2548 | tempdecl.visibility = sc.visibility; | |
0fb57034 | 2549 | tempdecl.userAttribDecl = sc.userAttribDecl; |
5fee5ec3 IB |
2550 | tempdecl.cppnamespace = sc.namespace; |
2551 | tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_); | |
2552 | tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_); | |
2553 | ||
2554 | UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage); | |
2555 | ||
2556 | if (!tempdecl.isstatic) | |
2557 | { | |
2558 | if (auto ad = tempdecl.parent.pastMixin().isAggregateDeclaration()) | |
2559 | ad.makeNested(); | |
2560 | } | |
2561 | ||
2562 | // Set up scope for parameters | |
2563 | auto paramsym = new ScopeDsymbol(); | |
2564 | paramsym.parent = tempdecl.parent; | |
2565 | Scope* paramscope = sc.push(paramsym); | |
2566 | paramscope.stc = 0; | |
2567 | ||
5eb9927a | 2568 | if (global.params.ddoc.doOutput) |
5fee5ec3 IB |
2569 | { |
2570 | tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.dim); | |
2571 | for (size_t i = 0; i < tempdecl.parameters.dim; i++) | |
2572 | { | |
2573 | TemplateParameter tp = (*tempdecl.parameters)[i]; | |
2574 | (*tempdecl.origParameters)[i] = tp.syntaxCopy(); | |
2575 | } | |
2576 | } | |
2577 | ||
2578 | for (size_t i = 0; i < tempdecl.parameters.dim; i++) | |
2579 | { | |
2580 | TemplateParameter tp = (*tempdecl.parameters)[i]; | |
2581 | if (!tp.declareParameter(paramscope)) | |
2582 | { | |
2583 | error(tp.loc, "parameter `%s` multiply defined", tp.ident.toChars()); | |
2584 | tempdecl.errors = true; | |
2585 | } | |
2586 | if (!tp.tpsemantic(paramscope, tempdecl.parameters)) | |
2587 | { | |
2588 | tempdecl.errors = true; | |
2589 | } | |
2590 | if (i + 1 != tempdecl.parameters.dim && tp.isTemplateTupleParameter()) | |
2591 | { | |
2592 | tempdecl.error("template tuple parameter must be last one"); | |
2593 | tempdecl.errors = true; | |
2594 | } | |
2595 | } | |
2596 | ||
2597 | /* Calculate TemplateParameter.dependent | |
2598 | */ | |
2599 | TemplateParameters tparams = TemplateParameters(1); | |
2600 | for (size_t i = 0; i < tempdecl.parameters.dim; i++) | |
2601 | { | |
2602 | TemplateParameter tp = (*tempdecl.parameters)[i]; | |
2603 | tparams[0] = tp; | |
2604 | ||
2605 | for (size_t j = 0; j < tempdecl.parameters.dim; j++) | |
2606 | { | |
2607 | // Skip cases like: X(T : T) | |
2608 | if (i == j) | |
2609 | continue; | |
2610 | ||
2611 | if (TemplateTypeParameter ttp = (*tempdecl.parameters)[j].isTemplateTypeParameter()) | |
2612 | { | |
2613 | if (reliesOnTident(ttp.specType, &tparams)) | |
2614 | tp.dependent = true; | |
2615 | } | |
2616 | else if (TemplateAliasParameter tap = (*tempdecl.parameters)[j].isTemplateAliasParameter()) | |
2617 | { | |
2618 | if (reliesOnTident(tap.specType, &tparams) || | |
2619 | reliesOnTident(isType(tap.specAlias), &tparams)) | |
2620 | { | |
2621 | tp.dependent = true; | |
2622 | } | |
2623 | } | |
2624 | } | |
2625 | } | |
2626 | ||
2627 | paramscope.pop(); | |
2628 | ||
2629 | // Compute again | |
2630 | tempdecl.onemember = null; | |
2631 | if (tempdecl.members) | |
2632 | { | |
2633 | Dsymbol s; | |
2634 | if (Dsymbol.oneMembers(tempdecl.members, &s, tempdecl.ident) && s) | |
2635 | { | |
2636 | tempdecl.onemember = s; | |
2637 | s.parent = tempdecl; | |
2638 | } | |
2639 | } | |
2640 | ||
2641 | /* BUG: should check: | |
2642 | * 1. template functions must not introduce virtual functions, as they | |
2643 | * cannot be accomodated in the vtbl[] | |
2644 | * 2. templates cannot introduce non-static data members (i.e. fields) | |
2645 | * as they would change the instance size of the aggregate. | |
2646 | */ | |
2647 | ||
2648 | tempdecl.semanticRun = PASS.semanticdone; | |
2649 | } | |
2650 | ||
2651 | override void visit(TemplateInstance ti) | |
2652 | { | |
2653 | templateInstanceSemantic(ti, sc, null); | |
2654 | } | |
2655 | ||
2656 | override void visit(TemplateMixin tm) | |
2657 | { | |
2658 | static if (LOG) | |
2659 | { | |
2660 | printf("+TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm); | |
2661 | fflush(stdout); | |
2662 | } | |
235d5a96 | 2663 | if (tm.semanticRun != PASS.initial) |
5fee5ec3 IB |
2664 | { |
2665 | // When a class/struct contains mixin members, and is done over | |
2666 | // because of forward references, never reach here so semanticRun | |
235d5a96 | 2667 | // has been reset to PASS.initial. |
5fee5ec3 IB |
2668 | static if (LOG) |
2669 | { | |
2670 | printf("\tsemantic done\n"); | |
2671 | } | |
2672 | return; | |
2673 | } | |
2674 | tm.semanticRun = PASS.semantic; | |
2675 | static if (LOG) | |
2676 | { | |
2677 | printf("\tdo semantic\n"); | |
2678 | } | |
2679 | ||
2680 | Scope* scx = null; | |
2681 | if (tm._scope) | |
2682 | { | |
2683 | sc = tm._scope; | |
2684 | scx = tm._scope; // save so we don't make redundant copies | |
2685 | tm._scope = null; | |
2686 | } | |
2687 | ||
2688 | /* Run semantic on each argument, place results in tiargs[], | |
2689 | * then find best match template with tiargs | |
2690 | */ | |
2691 | if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null)) | |
2692 | { | |
235d5a96 | 2693 | if (tm.semanticRun == PASS.initial) // forward reference had occurred |
5fee5ec3 IB |
2694 | { |
2695 | //printf("forward reference - deferring\n"); | |
2696 | return deferDsymbolSemantic(tm, scx); | |
2697 | } | |
2698 | ||
2699 | tm.inst = tm; | |
2700 | tm.errors = true; | |
2701 | return; // error recovery | |
2702 | } | |
2703 | ||
2704 | auto tempdecl = tm.tempdecl.isTemplateDeclaration(); | |
2705 | assert(tempdecl); | |
2706 | ||
2707 | if (!tm.ident) | |
2708 | { | |
2709 | /* Assign scope local unique identifier, as same as lambdas. | |
2710 | */ | |
2711 | const(char)[] s = "__mixin"; | |
2712 | ||
2713 | if (FuncDeclaration func = sc.parent.isFuncDeclaration()) | |
2714 | { | |
2715 | tm.symtab = func.localsymtab; | |
2716 | if (tm.symtab) | |
2717 | { | |
2718 | // Inside template constraint, symtab is not set yet. | |
2719 | goto L1; | |
2720 | } | |
2721 | } | |
2722 | else | |
2723 | { | |
2724 | tm.symtab = sc.parent.isScopeDsymbol().symtab; | |
2725 | L1: | |
2726 | assert(tm.symtab); | |
2727 | tm.ident = Identifier.generateId(s, tm.symtab.length + 1); | |
2728 | tm.symtab.insert(tm); | |
2729 | } | |
2730 | } | |
2731 | ||
2732 | tm.inst = tm; | |
2733 | tm.parent = sc.parent; | |
2734 | ||
2735 | /* Detect recursive mixin instantiations. | |
2736 | */ | |
2737 | for (Dsymbol s = tm.parent; s; s = s.parent) | |
2738 | { | |
2739 | //printf("\ts = '%s'\n", s.toChars()); | |
2740 | TemplateMixin tmix = s.isTemplateMixin(); | |
2741 | if (!tmix || tempdecl != tmix.tempdecl) | |
2742 | continue; | |
2743 | ||
2744 | /* Different argument list lengths happen with variadic args | |
2745 | */ | |
2746 | if (tm.tiargs.dim != tmix.tiargs.dim) | |
2747 | continue; | |
2748 | ||
2749 | for (size_t i = 0; i < tm.tiargs.dim; i++) | |
2750 | { | |
2751 | RootObject o = (*tm.tiargs)[i]; | |
2752 | Type ta = isType(o); | |
2753 | Expression ea = isExpression(o); | |
2754 | Dsymbol sa = isDsymbol(o); | |
2755 | RootObject tmo = (*tmix.tiargs)[i]; | |
2756 | if (ta) | |
2757 | { | |
2758 | Type tmta = isType(tmo); | |
2759 | if (!tmta) | |
2760 | goto Lcontinue; | |
2761 | if (!ta.equals(tmta)) | |
2762 | goto Lcontinue; | |
2763 | } | |
2764 | else if (ea) | |
2765 | { | |
2766 | Expression tme = isExpression(tmo); | |
2767 | if (!tme || !ea.equals(tme)) | |
2768 | goto Lcontinue; | |
2769 | } | |
2770 | else if (sa) | |
2771 | { | |
2772 | Dsymbol tmsa = isDsymbol(tmo); | |
2773 | if (sa != tmsa) | |
2774 | goto Lcontinue; | |
2775 | } | |
2776 | else | |
2777 | assert(0); | |
2778 | } | |
2779 | tm.error("recursive mixin instantiation"); | |
2780 | return; | |
2781 | ||
2782 | Lcontinue: | |
2783 | continue; | |
2784 | } | |
2785 | ||
2786 | // Copy the syntax trees from the TemplateDeclaration | |
2787 | tm.members = Dsymbol.arraySyntaxCopy(tempdecl.members); | |
2788 | if (!tm.members) | |
2789 | return; | |
2790 | ||
2791 | tm.symtab = new DsymbolTable(); | |
2792 | ||
2793 | sc.getScopesym().importScope(tm, Visibility(Visibility.Kind.public_)); | |
2794 | ||
2795 | static if (LOG) | |
2796 | { | |
2797 | printf("\tcreate scope for template parameters '%s'\n", tm.toChars()); | |
2798 | } | |
2799 | Scope* scy = sc.push(tm); | |
2800 | scy.parent = tm; | |
2801 | ||
2802 | /* https://issues.dlang.org/show_bug.cgi?id=930 | |
2803 | * | |
2804 | * If the template that is to be mixed in is in the scope of a template | |
2805 | * instance, we have to also declare the type aliases in the new mixin scope. | |
2806 | */ | |
2807 | auto parentInstance = tempdecl.parent ? tempdecl.parent.isTemplateInstance() : null; | |
2808 | if (parentInstance) | |
2809 | parentInstance.declareParameters(scy); | |
2810 | ||
2811 | tm.argsym = new ScopeDsymbol(); | |
2812 | tm.argsym.parent = scy.parent; | |
2813 | Scope* argscope = scy.push(tm.argsym); | |
2814 | ||
2815 | uint errorsave = global.errors; | |
2816 | ||
2817 | // Declare each template parameter as an alias for the argument type | |
2818 | tm.declareParameters(argscope); | |
2819 | ||
2820 | // Add members to enclosing scope, as well as this scope | |
2821 | tm.members.foreachDsymbol(s => s.addMember(argscope, tm)); | |
2822 | ||
2823 | // Do semantic() analysis on template instance members | |
2824 | static if (LOG) | |
2825 | { | |
2826 | printf("\tdo semantic() on template instance members '%s'\n", tm.toChars()); | |
2827 | } | |
2828 | Scope* sc2 = argscope.push(tm); | |
2829 | //size_t deferred_dim = Module.deferred.dim; | |
2830 | ||
2831 | __gshared int nest; | |
2832 | //printf("%d\n", nest); | |
2833 | if (++nest > global.recursionLimit) | |
2834 | { | |
2835 | global.gag = 0; // ensure error message gets printed | |
2836 | tm.error("recursive expansion"); | |
2837 | fatal(); | |
2838 | } | |
2839 | ||
2840 | tm.members.foreachDsymbol( s => s.setScope(sc2) ); | |
2841 | ||
2842 | tm.members.foreachDsymbol( s => s.importAll(sc2) ); | |
2843 | ||
2844 | tm.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) ); | |
2845 | ||
2846 | nest--; | |
2847 | ||
2848 | /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols. | |
2849 | * Because the members would already call Module.addDeferredSemantic() for themselves. | |
2850 | * See Struct, Class, Interface, and EnumDeclaration.dsymbolSemantic(). | |
2851 | */ | |
2852 | //if (!sc.func && Module.deferred.dim > deferred_dim) {} | |
2853 | ||
5eb9927a | 2854 | AggregateDeclaration ad = tm.isMember(); |
5fee5ec3 IB |
2855 | if (sc.func && !ad) |
2856 | { | |
2857 | tm.semantic2(sc2); | |
2858 | tm.semantic3(sc2); | |
2859 | } | |
2860 | ||
2861 | // Give additional context info if error occurred during instantiation | |
2862 | if (global.errors != errorsave) | |
2863 | { | |
2864 | tm.error("error instantiating"); | |
2865 | tm.errors = true; | |
2866 | } | |
2867 | ||
2868 | sc2.pop(); | |
2869 | argscope.pop(); | |
2870 | scy.pop(); | |
2871 | ||
2872 | static if (LOG) | |
2873 | { | |
2874 | printf("-TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm); | |
2875 | } | |
2876 | } | |
2877 | ||
2878 | override void visit(Nspace ns) | |
2879 | { | |
235d5a96 | 2880 | if (ns.semanticRun != PASS.initial) |
5fee5ec3 IB |
2881 | return; |
2882 | static if (LOG) | |
2883 | { | |
2884 | printf("+Nspace::semantic('%s')\n", ns.toChars()); | |
5eb9927a | 2885 | scope(exit) printf("-Nspace::semantic('%s')\n", ns.toChars()); |
5fee5ec3 IB |
2886 | } |
2887 | if (ns._scope) | |
2888 | { | |
2889 | sc = ns._scope; | |
2890 | ns._scope = null; | |
2891 | } | |
2892 | if (!sc) | |
2893 | return; | |
2894 | ||
2895 | bool repopulateMembers = false; | |
2896 | if (ns.identExp) | |
2897 | { | |
2898 | // resolve the namespace identifier | |
2899 | sc = sc.startCTFE(); | |
2900 | Expression resolved = ns.identExp.expressionSemantic(sc); | |
2901 | resolved = resolveProperties(sc, resolved); | |
2902 | sc = sc.endCTFE(); | |
2903 | resolved = resolved.ctfeInterpret(); | |
2904 | StringExp name = resolved.toStringExp(); | |
ae56e2da | 2905 | TupleExp tup = name ? null : resolved.isTupleExp(); |
5fee5ec3 IB |
2906 | if (!tup && !name) |
2907 | { | |
2908 | error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars()); | |
2909 | return; | |
2910 | } | |
2911 | ns.identExp = resolved; // we don't need to keep the old AST around | |
2912 | if (name) | |
2913 | { | |
2914 | const(char)[] ident = name.toStringz(); | |
2915 | if (ident.length == 0 || !Identifier.isValidIdentifier(ident)) | |
2916 | { | |
2917 | error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr); | |
2918 | return; | |
2919 | } | |
2920 | ns.ident = Identifier.idPool(ident); | |
2921 | } | |
2922 | else | |
2923 | { | |
2924 | // create namespace stack from the tuple | |
2925 | Nspace parentns = ns; | |
2926 | foreach (i, exp; *tup.exps) | |
2927 | { | |
2928 | name = exp.toStringExp(); | |
2929 | if (!name) | |
2930 | { | |
2931 | error(ns.loc, "expected string expression for namespace name, got `%s`", exp.toChars()); | |
2932 | return; | |
2933 | } | |
2934 | const(char)[] ident = name.toStringz(); | |
2935 | if (ident.length == 0 || !Identifier.isValidIdentifier(ident)) | |
2936 | { | |
2937 | error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr); | |
2938 | return; | |
2939 | } | |
2940 | if (i == 0) | |
2941 | { | |
2942 | ns.ident = Identifier.idPool(ident); | |
2943 | } | |
2944 | else | |
2945 | { | |
2946 | // insert the new namespace | |
2947 | Nspace childns = new Nspace(ns.loc, Identifier.idPool(ident), null, parentns.members); | |
2948 | parentns.members = new Dsymbols; | |
2949 | parentns.members.push(childns); | |
2950 | parentns = childns; | |
2951 | repopulateMembers = true; | |
2952 | } | |
2953 | } | |
2954 | } | |
2955 | } | |
2956 | ||
2957 | ns.semanticRun = PASS.semantic; | |
2958 | ns.parent = sc.parent; | |
2959 | // Link does not matter here, if the UDA is present it will error | |
2960 | UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp); | |
2961 | ||
5eb9927a IB |
2962 | if (!ns.members) |
2963 | { | |
2964 | ns.semanticRun = PASS.semanticdone; | |
2965 | return; | |
2966 | } | |
2967 | assert(sc); | |
2968 | sc = sc.push(ns); | |
2969 | sc.linkage = LINK.cpp; // note that namespaces imply C++ linkage | |
2970 | sc.parent = ns; | |
2971 | foreach (s; *ns.members) | |
5fee5ec3 | 2972 | { |
5eb9927a | 2973 | if (repopulateMembers) |
5fee5ec3 | 2974 | { |
5eb9927a IB |
2975 | s.addMember(sc, sc.scopesym); |
2976 | s.setScope(sc); | |
5fee5ec3 | 2977 | } |
5eb9927a IB |
2978 | s.importAll(sc); |
2979 | } | |
2980 | foreach (s; *ns.members) | |
2981 | { | |
2982 | static if (LOG) | |
5fee5ec3 | 2983 | { |
5eb9927a | 2984 | printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); |
5fee5ec3 | 2985 | } |
5eb9927a | 2986 | s.dsymbolSemantic(sc); |
5fee5ec3 | 2987 | } |
5eb9927a | 2988 | sc.pop(); |
5fee5ec3 | 2989 | ns.semanticRun = PASS.semanticdone; |
5fee5ec3 IB |
2990 | } |
2991 | ||
2992 | void funcDeclarationSemantic(FuncDeclaration funcdecl) | |
2993 | { | |
5fee5ec3 IB |
2994 | version (none) |
2995 | { | |
2996 | printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage); | |
2997 | if (funcdecl.isFuncLiteralDeclaration()) | |
2998 | printf("\tFuncLiteralDeclaration()\n"); | |
2999 | printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), funcdecl.parent ? funcdecl.parent.toChars() : ""); | |
3000 | printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars()); | |
3001 | } | |
3002 | ||
235d5a96 | 3003 | if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration()) |
5fee5ec3 IB |
3004 | { |
3005 | /* Member functions that have return types that are | |
3006 | * forward references can have semantic() run more than | |
3007 | * once on them. | |
3008 | * See test\interface2.d, test20 | |
3009 | */ | |
3010 | return; | |
3011 | } | |
3012 | ||
3013 | if (funcdecl.semanticRun >= PASS.semanticdone) | |
3014 | return; | |
3015 | assert(funcdecl.semanticRun <= PASS.semantic); | |
3016 | funcdecl.semanticRun = PASS.semantic; | |
3017 | ||
3018 | if (funcdecl._scope) | |
3019 | { | |
3020 | sc = funcdecl._scope; | |
3021 | funcdecl._scope = null; | |
3022 | } | |
3023 | ||
3024 | if (!sc || funcdecl.errors) | |
3025 | return; | |
3026 | ||
3027 | funcdecl.cppnamespace = sc.namespace; | |
3028 | funcdecl.parent = sc.parent; | |
3029 | Dsymbol parent = funcdecl.toParent(); | |
3030 | ||
3031 | funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function | |
3032 | ||
3033 | funcdecl.storage_class |= sc.stc & ~STC.ref_; | |
6384eff5 | 3034 | AggregateDeclaration ad = funcdecl.isThis(); |
5fee5ec3 IB |
3035 | // Don't nest structs b/c of generated methods which should not access the outer scopes. |
3036 | // https://issues.dlang.org/show_bug.cgi?id=16627 | |
235d5a96 | 3037 | if (ad && !funcdecl.isGenerated()) |
5fee5ec3 IB |
3038 | { |
3039 | funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_); | |
3040 | ad.makeNested(); | |
3041 | } | |
3042 | if (sc.func) | |
3043 | funcdecl.storage_class |= sc.func.storage_class & STC.disable; | |
3044 | // Remove prefix storage classes silently. | |
3045 | if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested())) | |
3046 | funcdecl.storage_class &= ~STC.TYPECTOR; | |
3047 | ||
31350635 | 3048 | //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal()); |
5fee5ec3 IB |
3049 | |
3050 | if (sc.flags & SCOPE.compile) | |
3051 | funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function | |
3052 | ||
5eb9927a | 3053 | funcdecl._linkage = sc.linkage; |
6384eff5 | 3054 | if (auto fld = funcdecl.isFuncLiteralDeclaration()) |
5fee5ec3 | 3055 | { |
6384eff5 IB |
3056 | if (fld.treq) |
3057 | { | |
3058 | Type treq = fld.treq; | |
3059 | assert(treq.nextOf().ty == Tfunction); | |
3060 | if (treq.ty == Tdelegate) | |
3061 | fld.tok = TOK.delegate_; | |
3062 | else if (treq.isPtrToFunction()) | |
3063 | fld.tok = TOK.function_; | |
3064 | else | |
3065 | assert(0); | |
5eb9927a | 3066 | funcdecl._linkage = treq.nextOf().toTypeFunction().linkage; |
6384eff5 | 3067 | } |
5fee5ec3 | 3068 | } |
5fee5ec3 IB |
3069 | |
3070 | // evaluate pragma(inline) | |
3071 | if (auto pragmadecl = sc.inlining) | |
3072 | funcdecl.inlining = pragmadecl.evalPragmaInline(sc); | |
3073 | ||
3074 | funcdecl.visibility = sc.visibility; | |
3075 | funcdecl.userAttribDecl = sc.userAttribDecl; | |
5eb9927a | 3076 | UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage); |
31350635 | 3077 | checkMustUseReserved(funcdecl); |
5fee5ec3 IB |
3078 | |
3079 | if (!funcdecl.originalType) | |
3080 | funcdecl.originalType = funcdecl.type.syntaxCopy(); | |
6384eff5 IB |
3081 | |
3082 | static TypeFunction getFunctionType(FuncDeclaration fd) | |
5fee5ec3 | 3083 | { |
6384eff5 IB |
3084 | if (auto tf = fd.type.isTypeFunction()) |
3085 | return tf; | |
3086 | ||
3087 | if (!fd.type.isTypeError()) | |
5fee5ec3 | 3088 | { |
6384eff5 IB |
3089 | fd.error("`%s` must be a function instead of `%s`", fd.toChars(), fd.type.toChars()); |
3090 | fd.type = Type.terror; | |
5fee5ec3 | 3091 | } |
6384eff5 IB |
3092 | fd.errors = true; |
3093 | return null; | |
5fee5ec3 | 3094 | } |
6384eff5 | 3095 | |
7e287503 IB |
3096 | if (sc.flags & SCOPE.Cfile) |
3097 | { | |
3098 | /* C11 allows a function to be declared with a typedef, D does not. | |
3099 | */ | |
3100 | if (auto ti = funcdecl.type.isTypeIdentifier()) | |
3101 | { | |
3102 | auto tj = ti.typeSemantic(funcdecl.loc, sc); | |
3103 | if (auto tjf = tj.isTypeFunction()) | |
3104 | { | |
3105 | /* Copy the type instead of just pointing to it, | |
3106 | * as we don't merge function types | |
3107 | */ | |
3108 | auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage); | |
3109 | funcdecl.type = tjf2; | |
3110 | funcdecl.originalType = tjf2; | |
3111 | } | |
3112 | } | |
3113 | } | |
3114 | ||
6384eff5 IB |
3115 | if (!getFunctionType(funcdecl)) |
3116 | return; | |
3117 | ||
5fee5ec3 IB |
3118 | if (!funcdecl.type.deco) |
3119 | { | |
3120 | sc = sc.push(); | |
3121 | sc.stc |= funcdecl.storage_class & (STC.disable | STC.deprecated_); // forward to function type | |
3122 | ||
3123 | TypeFunction tf = funcdecl.type.toTypeFunction(); | |
3124 | if (sc.func) | |
3125 | { | |
3126 | /* If the nesting parent is pure without inference, | |
3127 | * then this function defaults to pure too. | |
3128 | * | |
3129 | * auto foo() pure { | |
3130 | * auto bar() {} // become a weak purity function | |
3131 | * class C { // nested class | |
3132 | * auto baz() {} // become a weak purity function | |
3133 | * } | |
3134 | * | |
3135 | * static auto boo() {} // typed as impure | |
3136 | * // Even though, boo cannot call any impure functions. | |
3137 | * // See also Expression::checkPurity(). | |
3138 | * } | |
3139 | */ | |
3140 | if (tf.purity == PURE.impure && (funcdecl.isNested() || funcdecl.isThis())) | |
3141 | { | |
3142 | FuncDeclaration fd = null; | |
3143 | for (Dsymbol p = funcdecl.toParent2(); p; p = p.toParent2()) | |
3144 | { | |
3145 | if (AggregateDeclaration adx = p.isAggregateDeclaration()) | |
3146 | { | |
3147 | if (adx.isNested()) | |
3148 | continue; | |
3149 | break; | |
3150 | } | |
3151 | if ((fd = p.isFuncDeclaration()) !is null) | |
3152 | break; | |
3153 | } | |
3154 | ||
3155 | /* If the parent's purity is inferred, then this function's purity needs | |
3156 | * to be inferred first. | |
3157 | */ | |
3158 | if (fd && fd.isPureBypassingInference() >= PURE.weak && !funcdecl.isInstantiated()) | |
3159 | { | |
3160 | tf.purity = PURE.fwdref; // default to pure | |
3161 | } | |
3162 | } | |
3163 | } | |
3164 | ||
3165 | if (tf.isref) | |
3166 | sc.stc |= STC.ref_; | |
3167 | if (tf.isScopeQual) | |
3168 | sc.stc |= STC.scope_; | |
3169 | if (tf.isnothrow) | |
3170 | sc.stc |= STC.nothrow_; | |
3171 | if (tf.isnogc) | |
3172 | sc.stc |= STC.nogc; | |
3173 | if (tf.isproperty) | |
3174 | sc.stc |= STC.property; | |
3175 | if (tf.purity == PURE.fwdref) | |
3176 | sc.stc |= STC.pure_; | |
6384eff5 | 3177 | |
5fee5ec3 | 3178 | if (tf.trust != TRUST.default_) |
6384eff5 | 3179 | { |
5fee5ec3 | 3180 | sc.stc &= ~STC.safeGroup; |
6384eff5 IB |
3181 | if (tf.trust == TRUST.safe) |
3182 | sc.stc |= STC.safe; | |
3183 | else if (tf.trust == TRUST.system) | |
3184 | sc.stc |= STC.system; | |
3185 | else if (tf.trust == TRUST.trusted) | |
3186 | sc.stc |= STC.trusted; | |
3187 | } | |
5fee5ec3 IB |
3188 | |
3189 | if (funcdecl.isCtorDeclaration()) | |
3190 | { | |
3191 | tf.isctor = true; | |
3192 | Type tret = ad.handleType(); | |
3193 | assert(tret); | |
3194 | tret = tret.addStorageClass(funcdecl.storage_class | sc.stc); | |
3195 | tret = tret.addMod(funcdecl.type.mod); | |
3196 | tf.next = tret; | |
3197 | if (ad.isStructDeclaration()) | |
3198 | sc.stc |= STC.ref_; | |
3199 | } | |
3200 | ||
3201 | // 'return' on a non-static class member function implies 'scope' as well | |
3202 | if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_)) | |
3203 | sc.stc |= STC.scope_; | |
3204 | ||
3205 | // If 'this' has no pointers, remove 'scope' as it has no meaning | |
d97f3bca IB |
3206 | // Note: this is already covered by semantic of `VarDeclaration` and `TypeFunction`, |
3207 | // but existing code relies on `hasPointers()` being called here to resolve forward references: | |
3208 | // https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573 | |
5fee5ec3 IB |
3209 | if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers()) |
3210 | { | |
3211 | sc.stc &= ~STC.scope_; | |
3212 | tf.isScopeQual = false; | |
d97f3bca IB |
3213 | if (tf.isreturnscope) |
3214 | { | |
3215 | sc.stc &= ~(STC.return_ | STC.returnScope); | |
3216 | tf.isreturn = false; | |
3217 | tf.isreturnscope = false; | |
3218 | } | |
5fee5ec3 IB |
3219 | } |
3220 | ||
5eb9927a | 3221 | sc.linkage = funcdecl._linkage; |
5fee5ec3 IB |
3222 | |
3223 | if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) | |
3224 | { | |
3225 | OutBuffer buf; | |
3226 | MODtoBuffer(&buf, tf.mod); | |
3227 | funcdecl.error("without `this` cannot be `%s`", buf.peekChars()); | |
3228 | tf.mod = 0; // remove qualifiers | |
3229 | } | |
3230 | ||
3231 | /* Apply const, immutable, wild and shared storage class | |
3232 | * to the function type. Do this before type semantic. | |
3233 | */ | |
3234 | auto stc = funcdecl.storage_class; | |
3235 | if (funcdecl.type.isImmutable()) | |
3236 | stc |= STC.immutable_; | |
3237 | if (funcdecl.type.isConst()) | |
3238 | stc |= STC.const_; | |
3239 | if (funcdecl.type.isShared() || funcdecl.storage_class & STC.synchronized_) | |
3240 | stc |= STC.shared_; | |
3241 | if (funcdecl.type.isWild()) | |
3242 | stc |= STC.wild; | |
3243 | funcdecl.type = funcdecl.type.addSTC(stc); | |
3244 | ||
3245 | funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc); | |
3246 | sc = sc.pop(); | |
3247 | } | |
6384eff5 IB |
3248 | |
3249 | auto f = getFunctionType(funcdecl); | |
3250 | if (!f) | |
3251 | return; // funcdecl's type is not a function | |
3252 | ||
5fee5ec3 IB |
3253 | { |
3254 | // Merge back function attributes into 'originalType'. | |
3255 | // It's used for mangling, ddoc, and json output. | |
3256 | TypeFunction tfo = funcdecl.originalType.toTypeFunction(); | |
6384eff5 IB |
3257 | tfo.mod = f.mod; |
3258 | tfo.isScopeQual = f.isScopeQual; | |
3259 | tfo.isreturninferred = f.isreturninferred; | |
3260 | tfo.isscopeinferred = f.isscopeinferred; | |
3261 | tfo.isref = f.isref; | |
3262 | tfo.isnothrow = f.isnothrow; | |
3263 | tfo.isnogc = f.isnogc; | |
3264 | tfo.isproperty = f.isproperty; | |
3265 | tfo.purity = f.purity; | |
3266 | tfo.trust = f.trust; | |
5fee5ec3 IB |
3267 | |
3268 | funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); | |
3269 | } | |
3270 | ||
5eb9927a IB |
3271 | // check pragma(crt_constructor) signature |
3272 | if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor)) | |
3273 | { | |
3274 | const idStr = (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor" : "crt_destructor"; | |
3275 | if (f.nextOf().ty != Tvoid) | |
3276 | funcdecl.error("must return `void` for `pragma(%s)`", idStr.ptr); | |
3277 | if (funcdecl._linkage != LINK.c && f.parameterList.length != 0) | |
3278 | funcdecl.error("must be `extern(C)` for `pragma(%s)` when taking parameters", idStr.ptr); | |
3279 | } | |
3280 | ||
6384eff5 IB |
3281 | if (funcdecl.overnext && funcdecl.isCsymbol()) |
3282 | { | |
3283 | /* C does not allow function overloading, but it does allow | |
3284 | * redeclarations of the same function. If .overnext points | |
3285 | * to a redeclaration, ok. Error if it is an overload. | |
3286 | */ | |
3287 | auto fnext = funcdecl.overnext.isFuncDeclaration(); | |
3288 | funcDeclarationSemantic(fnext); | |
3289 | auto fn = fnext.type.isTypeFunction(); | |
3290 | if (!fn || !cFuncEquivalence(f, fn)) | |
3291 | { | |
3292 | funcdecl.error("redeclaration with different type"); | |
3293 | //printf("t1: %s\n", f.toChars()); | |
3294 | //printf("t2: %s\n", fn.toChars()); | |
3295 | } | |
3296 | funcdecl.overnext = null; // don't overload the redeclarations | |
3297 | } | |
5fee5ec3 IB |
3298 | |
3299 | if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType) | |
3300 | funcdecl.error("storage class `auto` has no effect if return type is not inferred"); | |
3301 | ||
5fee5ec3 IB |
3302 | if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested()) |
3303 | { | |
3304 | /* Non-static nested functions have a hidden 'this' pointer to which | |
3305 | * the 'return' applies | |
3306 | */ | |
3307 | if (sc.scopesym && sc.scopesym.isAggregateDeclaration()) | |
3308 | funcdecl.error("`static` member has no `this` to which `return` can apply"); | |
3309 | else | |
235d5a96 | 3310 | error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars()); |
5fee5ec3 IB |
3311 | } |
3312 | ||
3313 | if (funcdecl.isAbstract() && !funcdecl.isVirtual()) | |
3314 | { | |
3315 | const(char)* sfunc; | |
3316 | if (funcdecl.isStatic()) | |
3317 | sfunc = "static"; | |
3318 | else if (funcdecl.visibility.kind == Visibility.Kind.private_ || funcdecl.visibility.kind == Visibility.Kind.package_) | |
3319 | sfunc = visibilityToChars(funcdecl.visibility.kind); | |
3320 | else | |
3321 | sfunc = "final"; | |
3322 | funcdecl.error("`%s` functions cannot be `abstract`", sfunc); | |
3323 | } | |
3324 | ||
3325 | if (funcdecl.isOverride() && !funcdecl.isVirtual() && !funcdecl.isFuncLiteralDeclaration()) | |
3326 | { | |
3327 | Visibility.Kind kind = funcdecl.visible().kind; | |
3328 | if ((kind == Visibility.Kind.private_ || kind == Visibility.Kind.package_) && funcdecl.isMember()) | |
3329 | funcdecl.error("`%s` method is not virtual and cannot override", visibilityToChars(kind)); | |
3330 | else | |
3331 | funcdecl.error("cannot override a non-virtual function"); | |
3332 | } | |
3333 | ||
3334 | if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) | |
3335 | funcdecl.error("cannot be both `final` and `abstract`"); | |
3336 | version (none) | |
3337 | { | |
3338 | if (funcdecl.isAbstract() && funcdecl.fbody) | |
3339 | funcdecl.error("`abstract` functions cannot have bodies"); | |
3340 | } | |
3341 | ||
3342 | version (none) | |
3343 | { | |
3344 | if (funcdecl.isStaticConstructor() || funcdecl.isStaticDestructor()) | |
3345 | { | |
3346 | if (!funcdecl.isStatic() || funcdecl.type.nextOf().ty != Tvoid) | |
3347 | funcdecl.error("static constructors / destructors must be `static void`"); | |
3348 | if (f.arguments && f.arguments.dim) | |
3349 | funcdecl.error("static constructors / destructors must have empty parameter list"); | |
3350 | // BUG: check for invalid storage classes | |
3351 | } | |
3352 | } | |
3353 | ||
3354 | if (const pors = sc.flags & (SCOPE.printf | SCOPE.scanf)) | |
3355 | { | |
3356 | /* printf/scanf-like functions must be of the form: | |
3357 | * extern (C/C++) T printf([parameters...], const(char)* format, ...); | |
3358 | * or: | |
3359 | * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); | |
3360 | */ | |
3361 | ||
3362 | static bool isPointerToChar(Parameter p) | |
3363 | { | |
3364 | if (auto tptr = p.type.isTypePointer()) | |
3365 | { | |
3366 | return tptr.next.ty == Tchar; | |
3367 | } | |
3368 | return false; | |
3369 | } | |
3370 | ||
3371 | bool isVa_list(Parameter p) | |
3372 | { | |
3373 | return p.type.equals(target.va_listType(funcdecl.loc, sc)); | |
3374 | } | |
3375 | ||
3376 | const nparams = f.parameterList.length; | |
3377 | if ((f.linkage == LINK.c || f.linkage == LINK.cpp) && | |
3378 | ||
3379 | (f.parameterList.varargs == VarArg.variadic && | |
3380 | nparams >= 1 && | |
3381 | isPointerToChar(f.parameterList[nparams - 1]) || | |
3382 | ||
3383 | f.parameterList.varargs == VarArg.none && | |
3384 | nparams >= 2 && | |
3385 | isPointerToChar(f.parameterList[nparams - 2]) && | |
3386 | isVa_list(f.parameterList[nparams - 1]) | |
3387 | ) | |
3388 | ) | |
3389 | { | |
3390 | funcdecl.flags |= (pors == SCOPE.printf) ? FUNCFLAG.printf : FUNCFLAG.scanf; | |
3391 | } | |
3392 | else | |
3393 | { | |
3394 | const p = (pors == SCOPE.printf ? Id.printf : Id.scanf).toChars(); | |
3395 | if (f.parameterList.varargs == VarArg.variadic) | |
3396 | { | |
3397 | funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`" | |
3398 | ~ " not `%s`", | |
3399 | p, f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars()); | |
3400 | } | |
3401 | else | |
3402 | { | |
3403 | funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`", | |
3404 | p, f.next.toChars(), funcdecl.toChars()); | |
3405 | } | |
3406 | } | |
3407 | } | |
3408 | ||
6384eff5 | 3409 | if (auto id = parent.isInterfaceDeclaration()) |
5fee5ec3 IB |
3410 | { |
3411 | funcdecl.storage_class |= STC.abstract_; | |
3412 | if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete()) | |
3413 | funcdecl.error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface `%s`", id.toChars()); | |
3414 | if (funcdecl.fbody && funcdecl.isVirtual()) | |
3415 | funcdecl.error("function body only allowed in `final` functions in interface `%s`", id.toChars()); | |
3416 | } | |
6384eff5 | 3417 | |
5fee5ec3 IB |
3418 | if (UnionDeclaration ud = parent.isUnionDeclaration()) |
3419 | { | |
3420 | if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration()) | |
3421 | funcdecl.error("destructors, postblits and invariants are not allowed in union `%s`", ud.toChars()); | |
3422 | } | |
3423 | ||
3424 | if (StructDeclaration sd = parent.isStructDeclaration()) | |
3425 | { | |
3426 | if (funcdecl.isCtorDeclaration()) | |
3427 | { | |
3428 | goto Ldone; | |
3429 | } | |
3430 | } | |
3431 | ||
3432 | if (ClassDeclaration cd = parent.isClassDeclaration()) | |
3433 | { | |
3434 | parent = cd = objc.getParent(funcdecl, cd); | |
3435 | ||
3436 | if (funcdecl.isCtorDeclaration()) | |
3437 | { | |
3438 | goto Ldone; | |
3439 | } | |
3440 | ||
3441 | if (funcdecl.storage_class & STC.abstract_) | |
3442 | cd.isabstract = ThreeState.yes; | |
3443 | ||
3444 | // if static function, do not put in vtbl[] | |
3445 | if (!funcdecl.isVirtual()) | |
3446 | { | |
3447 | //printf("\tnot virtual\n"); | |
3448 | goto Ldone; | |
3449 | } | |
3450 | // Suppress further errors if the return type is an error | |
3451 | if (funcdecl.type.nextOf() == Type.terror) | |
3452 | goto Ldone; | |
3453 | ||
3454 | bool may_override = false; | |
3455 | for (size_t i = 0; i < cd.baseclasses.dim; i++) | |
3456 | { | |
3457 | BaseClass* b = (*cd.baseclasses)[i]; | |
3458 | ClassDeclaration cbd = b.type.toBasetype().isClassHandle(); | |
3459 | if (!cbd) | |
3460 | continue; | |
3461 | for (size_t j = 0; j < cbd.vtbl.dim; j++) | |
3462 | { | |
3463 | FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration(); | |
3464 | if (!f2 || f2.ident != funcdecl.ident) | |
3465 | continue; | |
3466 | if (cbd.parent && cbd.parent.isTemplateInstance()) | |
3467 | { | |
3468 | if (!f2.functionSemantic()) | |
3469 | goto Ldone; | |
3470 | } | |
3471 | may_override = true; | |
3472 | } | |
3473 | } | |
3474 | if (may_override && funcdecl.type.nextOf() is null) | |
3475 | { | |
3476 | /* If same name function exists in base class but 'this' is auto return, | |
3477 | * cannot find index of base class's vtbl[] to override. | |
3478 | */ | |
3479 | funcdecl.error("return type inference is not supported if may override base class function"); | |
3480 | } | |
3481 | ||
3482 | /* Find index of existing function in base class's vtbl[] to override | |
3483 | * (the index will be the same as in cd's current vtbl[]) | |
3484 | */ | |
3485 | int vi = cd.baseClass ? funcdecl.findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.dim) : -1; | |
3486 | ||
3487 | bool doesoverride = false; | |
3488 | switch (vi) | |
3489 | { | |
3490 | case -1: | |
3491 | Lintro: | |
3492 | /* Didn't find one, so | |
3493 | * This is an 'introducing' function which gets a new | |
3494 | * slot in the vtbl[]. | |
3495 | */ | |
3496 | ||
3497 | // Verify this doesn't override previous final function | |
3498 | if (cd.baseClass) | |
3499 | { | |
3500 | Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident); | |
3501 | if (s) | |
3502 | { | |
6384eff5 | 3503 | if (auto f2 = s.isFuncDeclaration()) |
5fee5ec3 IB |
3504 | { |
3505 | f2 = f2.overloadExactMatch(funcdecl.type); | |
3506 | if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) | |
3507 | funcdecl.error("cannot override `final` function `%s`", f2.toPrettyChars()); | |
3508 | } | |
3509 | } | |
3510 | } | |
3511 | ||
d7569187 IB |
3512 | /* These quirky conditions mimic what happens when virtual |
3513 | inheritance is implemented by producing a virtual base table | |
3514 | with offsets to each of the virtual bases. | |
5fee5ec3 | 3515 | */ |
d7569187 | 3516 | if (target.cpp.splitVBasetable && cd.classKind == ClassKind.cpp && |
5fee5ec3 IB |
3517 | cd.baseClass && cd.baseClass.vtbl.dim) |
3518 | { | |
3519 | /* if overriding an interface function, then this is not | |
3520 | * introducing and don't put it in the class vtbl[] | |
3521 | */ | |
3522 | funcdecl.interfaceVirtual = funcdecl.overrideInterface(); | |
3523 | if (funcdecl.interfaceVirtual) | |
3524 | { | |
3525 | //printf("\tinterface function %s\n", toChars()); | |
3526 | cd.vtblFinal.push(funcdecl); | |
3527 | goto Linterfaces; | |
3528 | } | |
3529 | } | |
3530 | ||
3531 | if (funcdecl.isFinalFunc()) | |
3532 | { | |
3533 | // Don't check here, as it may override an interface function | |
3534 | //if (isOverride()) | |
3535 | // error("is marked as override, but does not override any function"); | |
3536 | cd.vtblFinal.push(funcdecl); | |
3537 | } | |
3538 | else | |
3539 | { | |
3540 | //printf("\tintroducing function %s\n", funcdecl.toChars()); | |
235d5a96 | 3541 | funcdecl.flags |= FUNCFLAG.introducing; |
5fee5ec3 IB |
3542 | if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads) |
3543 | { | |
3544 | /* Overloaded functions with same name are grouped and in reverse order. | |
3545 | * Search for first function of overload group, and insert | |
3546 | * funcdecl into vtbl[] immediately before it. | |
3547 | */ | |
3548 | funcdecl.vtblIndex = cast(int)cd.vtbl.dim; | |
3549 | bool found; | |
3550 | foreach (const i, s; cd.vtbl) | |
3551 | { | |
3552 | if (found) | |
3553 | // the rest get shifted forward | |
3554 | ++s.isFuncDeclaration().vtblIndex; | |
3555 | else if (s.ident == funcdecl.ident && s.parent == parent) | |
3556 | { | |
3557 | // found first function of overload group | |
3558 | funcdecl.vtblIndex = cast(int)i; | |
3559 | found = true; | |
3560 | ++s.isFuncDeclaration().vtblIndex; | |
3561 | } | |
3562 | } | |
3563 | cd.vtbl.insert(funcdecl.vtblIndex, funcdecl); | |
3564 | ||
3565 | debug foreach (const i, s; cd.vtbl) | |
3566 | { | |
3567 | // a C++ dtor gets its vtblIndex later (and might even be added twice to the vtbl), | |
3568 | // e.g. when compiling druntime with a debug compiler, namely with core.stdcpp.exception. | |
3569 | if (auto fd = s.isFuncDeclaration()) | |
3570 | assert(fd.vtblIndex == i || | |
3571 | (cd.classKind == ClassKind.cpp && fd.isDtorDeclaration) || | |
3572 | funcdecl.parent.isInterfaceDeclaration); // interface functions can be in multiple vtbls | |
3573 | } | |
3574 | } | |
3575 | else | |
3576 | { | |
3577 | // Append to end of vtbl[] | |
3578 | vi = cast(int)cd.vtbl.dim; | |
3579 | cd.vtbl.push(funcdecl); | |
3580 | funcdecl.vtblIndex = vi; | |
3581 | } | |
3582 | } | |
3583 | break; | |
3584 | ||
3585 | case -2: | |
3586 | // can't determine because of forward references | |
3587 | funcdecl.errors = true; | |
3588 | return; | |
3589 | ||
3590 | default: | |
3591 | { | |
7e287503 IB |
3592 | if (vi >= cd.vtbl.length) |
3593 | { | |
3594 | /* the derived class cd doesn't have its vtbl[] allocated yet. | |
3595 | * https://issues.dlang.org/show_bug.cgi?id=21008 | |
3596 | */ | |
3597 | funcdecl.error("circular reference to class `%s`", cd.toChars()); | |
3598 | funcdecl.errors = true; | |
3599 | return; | |
3600 | } | |
5fee5ec3 IB |
3601 | FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); |
3602 | FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); | |
3603 | // This function is covariant with fdv | |
3604 | ||
3605 | if (fdc == funcdecl) | |
3606 | { | |
3607 | doesoverride = true; | |
3608 | break; | |
3609 | } | |
3610 | ||
610d7898 IB |
3611 | auto vtf = getFunctionType(fdv); |
3612 | if (vtf.trust > TRUST.system && f.trust == TRUST.system) | |
3613 | funcdecl.error("cannot override `@safe` method `%s` with a `@system` attribute", | |
3614 | fdv.toPrettyChars); | |
3615 | ||
5fee5ec3 IB |
3616 | if (fdc.toParent() == parent) |
3617 | { | |
3618 | //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", | |
3619 | // vi, this, this.toChars(), this.type.toChars(), this.loc.toChars(), | |
3620 | // fdc, fdc .toChars(), fdc .type.toChars(), fdc .loc.toChars(), | |
3621 | // fdv, fdv .toChars(), fdv .type.toChars(), fdv .loc.toChars()); | |
3622 | ||
3623 | // fdc overrides fdv exactly, then this introduces new function. | |
3624 | if (fdc.type.mod == fdv.type.mod && funcdecl.type.mod != fdv.type.mod) | |
3625 | goto Lintro; | |
3626 | } | |
3627 | ||
d7569187 | 3628 | if (fdv.isDeprecated && !funcdecl.isDeprecated) |
5fee5ec3 IB |
3629 | deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`", |
3630 | funcdecl.toPrettyChars, fdv.toPrettyChars); | |
3631 | ||
3632 | // This function overrides fdv | |
3633 | if (fdv.isFinalFunc()) | |
3634 | funcdecl.error("cannot override `final` function `%s`", fdv.toPrettyChars()); | |
3635 | ||
3636 | if (!funcdecl.isOverride()) | |
3637 | { | |
3638 | if (fdv.isFuture()) | |
3639 | { | |
3640 | deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars()); | |
3641 | // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] | |
3642 | goto Lintro; | |
3643 | } | |
3644 | else | |
3645 | { | |
3646 | // https://issues.dlang.org/show_bug.cgi?id=17349 | |
3647 | error(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", | |
3648 | fdv.toPrettyChars(), funcdecl.toPrettyChars()); | |
3649 | } | |
3650 | } | |
3651 | doesoverride = true; | |
3652 | if (fdc.toParent() == parent) | |
3653 | { | |
3654 | // If both are mixins, or both are not, then error. | |
3655 | // If either is not, the one that is not overrides the other. | |
3656 | bool thismixin = funcdecl.parent.isClassDeclaration() !is null; | |
3657 | bool fdcmixin = fdc.parent.isClassDeclaration() !is null; | |
3658 | if (thismixin == fdcmixin) | |
3659 | { | |
3660 | funcdecl.error("multiple overrides of same function"); | |
3661 | } | |
3662 | /* | |
3663 | * https://issues.dlang.org/show_bug.cgi?id=711 | |
3664 | * | |
3665 | * If an overriding method is introduced through a mixin, | |
3666 | * we need to update the vtbl so that both methods are | |
3667 | * present. | |
3668 | */ | |
3669 | else if (thismixin) | |
3670 | { | |
3671 | /* if the mixin introduced the overriding method, then reintroduce it | |
3672 | * in the vtbl. The initial entry for the mixined method | |
3673 | * will be updated at the end of the enclosing `if` block | |
3674 | * to point to the current (non-mixined) function. | |
3675 | */ | |
3676 | auto vitmp = cast(int)cd.vtbl.dim; | |
3677 | cd.vtbl.push(fdc); | |
3678 | fdc.vtblIndex = vitmp; | |
3679 | } | |
3680 | else if (fdcmixin) | |
3681 | { | |
3682 | /* if the current overriding function is coming from a | |
3683 | * mixined block, then push the current function in the | |
3684 | * vtbl, but keep the previous (non-mixined) function as | |
3685 | * the overriding one. | |
3686 | */ | |
3687 | auto vitmp = cast(int)cd.vtbl.dim; | |
3688 | cd.vtbl.push(funcdecl); | |
3689 | funcdecl.vtblIndex = vitmp; | |
3690 | break; | |
3691 | } | |
3692 | else // fdc overrides fdv | |
3693 | { | |
3694 | // this doesn't override any function | |
3695 | break; | |
3696 | } | |
3697 | } | |
3698 | cd.vtbl[vi] = funcdecl; | |
3699 | funcdecl.vtblIndex = vi; | |
3700 | ||
3701 | /* Remember which functions this overrides | |
3702 | */ | |
3703 | funcdecl.foverrides.push(fdv); | |
3704 | ||
3705 | /* This works by whenever this function is called, | |
3706 | * it actually returns tintro, which gets dynamically | |
3707 | * cast to type. But we know that tintro is a base | |
3708 | * of type, so we could optimize it by not doing a | |
3709 | * dynamic cast, but just subtracting the isBaseOf() | |
3710 | * offset if the value is != null. | |
3711 | */ | |
3712 | ||
3713 | if (fdv.tintro) | |
3714 | funcdecl.tintro = fdv.tintro; | |
3715 | else if (!funcdecl.type.equals(fdv.type)) | |
3716 | { | |
d7569187 IB |
3717 | auto tnext = funcdecl.type.nextOf(); |
3718 | if (auto handle = tnext.isClassHandle()) | |
3719 | { | |
3720 | if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) | |
3721 | handle.dsymbolSemantic(null); | |
3722 | } | |
5fee5ec3 IB |
3723 | /* Only need to have a tintro if the vptr |
3724 | * offsets differ | |
3725 | */ | |
3726 | int offset; | |
d7569187 | 3727 | if (fdv.type.nextOf().isBaseOf(tnext, &offset)) |
5fee5ec3 IB |
3728 | { |
3729 | funcdecl.tintro = fdv.type; | |
3730 | } | |
3731 | } | |
3732 | break; | |
3733 | } | |
3734 | } | |
3735 | ||
3736 | /* Go through all the interface bases. | |
3737 | * If this function is covariant with any members of those interface | |
3738 | * functions, set the tintro. | |
3739 | */ | |
3740 | Linterfaces: | |
3741 | bool foundVtblMatch = false; | |
3742 | ||
3743 | for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass) | |
3744 | { | |
3745 | foreach (b; bcd.interfaces) | |
3746 | { | |
3747 | vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim); | |
3748 | switch (vi) | |
3749 | { | |
3750 | case -1: | |
3751 | break; | |
3752 | ||
3753 | case -2: | |
3754 | // can't determine because of forward references | |
3755 | funcdecl.errors = true; | |
3756 | return; | |
3757 | ||
3758 | default: | |
3759 | { | |
3760 | auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi]; | |
3761 | Type ti = null; | |
3762 | ||
3763 | foundVtblMatch = true; | |
3764 | ||
3765 | /* Remember which functions this overrides | |
3766 | */ | |
3767 | funcdecl.foverrides.push(fdv); | |
3768 | ||
3769 | /* Should we really require 'override' when implementing | |
3770 | * an interface function? | |
3771 | */ | |
3772 | //if (!isOverride()) | |
3773 | // warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars()); | |
3774 | ||
3775 | if (fdv.tintro) | |
3776 | ti = fdv.tintro; | |
3777 | else if (!funcdecl.type.equals(fdv.type)) | |
3778 | { | |
3779 | /* Only need to have a tintro if the vptr | |
3780 | * offsets differ | |
3781 | */ | |
3782 | int offset; | |
3783 | if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset)) | |
3784 | { | |
3785 | ti = fdv.type; | |
3786 | } | |
3787 | } | |
3788 | if (ti) | |
3789 | { | |
3790 | if (funcdecl.tintro) | |
3791 | { | |
3792 | if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null)) | |
3793 | { | |
3794 | funcdecl.error("incompatible covariant types `%s` and `%s`", funcdecl.tintro.toChars(), ti.toChars()); | |
3795 | } | |
3796 | } | |
3797 | else | |
3798 | { | |
3799 | funcdecl.tintro = ti; | |
3800 | } | |
3801 | } | |
3802 | } | |
3803 | } | |
3804 | } | |
3805 | } | |
3806 | if (foundVtblMatch) | |
3807 | { | |
3808 | goto L2; | |
3809 | } | |
3810 | ||
3811 | if (!doesoverride && funcdecl.isOverride() && (funcdecl.type.nextOf() || !may_override)) | |
3812 | { | |
3813 | BaseClass* bc = null; | |
3814 | Dsymbol s = null; | |
3815 | for (size_t i = 0; i < cd.baseclasses.dim; i++) | |
3816 | { | |
3817 | bc = (*cd.baseclasses)[i]; | |
3818 | s = bc.sym.search_correct(funcdecl.ident); | |
3819 | if (s) | |
3820 | break; | |
3821 | } | |
3822 | ||
3823 | if (s) | |
3824 | { | |
3825 | HdrGenState hgs; | |
3826 | OutBuffer buf; | |
3827 | ||
3828 | auto fd = s.isFuncDeclaration(); | |
3829 | functionToBufferFull(cast(TypeFunction)(funcdecl.type), &buf, | |
3830 | new Identifier(funcdecl.toPrettyChars()), &hgs, null); | |
3831 | const(char)* funcdeclToChars = buf.peekChars(); | |
3832 | ||
3833 | if (fd) | |
3834 | { | |
3835 | OutBuffer buf1; | |
3836 | ||
3837 | if (fd.ident == funcdecl.ident) | |
3838 | hgs.fullQual = true; | |
3839 | functionToBufferFull(cast(TypeFunction)(fd.type), &buf1, | |
3840 | new Identifier(fd.toPrettyChars()), &hgs, null); | |
3841 | ||
3842 | error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", | |
3843 | funcdeclToChars, buf1.peekChars()); | |
3844 | } | |
3845 | else | |
3846 | { | |
3847 | error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?", | |
3848 | funcdeclToChars, s.kind, s.toPrettyChars()); | |
3849 | errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overriden"); | |
3850 | } | |
3851 | } | |
3852 | else | |
3853 | funcdecl.error("does not override any function"); | |
3854 | } | |
3855 | ||
3856 | L2: | |
3857 | objc.setSelector(funcdecl, sc); | |
3858 | objc.checkLinkage(funcdecl); | |
3859 | objc.addToClassMethodList(funcdecl, cd); | |
3860 | objc.setAsOptional(funcdecl, sc); | |
3861 | ||
3862 | /* Go through all the interface bases. | |
3863 | * Disallow overriding any final functions in the interface(s). | |
3864 | */ | |
3865 | foreach (b; cd.interfaces) | |
3866 | { | |
3867 | if (b.sym) | |
3868 | { | |
6384eff5 | 3869 | if (auto s = search_function(b.sym, funcdecl.ident)) |
5fee5ec3 | 3870 | { |
6384eff5 | 3871 | if (auto f2 = s.isFuncDeclaration()) |
5fee5ec3 IB |
3872 | { |
3873 | f2 = f2.overloadExactMatch(funcdecl.type); | |
3874 | if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) | |
3875 | funcdecl.error("cannot override `final` function `%s.%s`", b.sym.toChars(), f2.toPrettyChars()); | |
3876 | } | |
3877 | } | |
3878 | } | |
3879 | } | |
3880 | ||
3881 | if (funcdecl.isOverride) | |
3882 | { | |
3883 | if (funcdecl.storage_class & STC.disable) | |
3884 | deprecation(funcdecl.loc, | |
3885 | "`%s` cannot be annotated with `@disable` because it is overriding a function in the base class", | |
3886 | funcdecl.toPrettyChars); | |
d7569187 IB |
3887 | |
3888 | if (funcdecl.isDeprecated && !(funcdecl.foverrides.length && funcdecl.foverrides[0].isDeprecated)) | |
5fee5ec3 IB |
3889 | deprecation(funcdecl.loc, |
3890 | "`%s` cannot be marked as `deprecated` because it is overriding a function in the base class", | |
3891 | funcdecl.toPrettyChars); | |
3892 | } | |
3893 | ||
3894 | } | |
3895 | else if (funcdecl.isOverride() && !parent.isTemplateInstance()) | |
3896 | funcdecl.error("`override` only applies to class member functions"); | |
3897 | ||
3898 | if (auto ti = parent.isTemplateInstance) | |
3899 | { | |
3900 | objc.setSelector(funcdecl, sc); | |
3901 | objc.setAsOptional(funcdecl, sc); | |
3902 | } | |
3903 | ||
3904 | objc.validateSelector(funcdecl); | |
3905 | objc.validateOptional(funcdecl); | |
3906 | // Reflect this.type to f because it could be changed by findVtblIndex | |
3907 | f = funcdecl.type.toTypeFunction(); | |
3908 | ||
3909 | Ldone: | |
3910 | if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody()) | |
3911 | funcdecl.error("`in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract"); | |
3912 | ||
3913 | /* Do not allow template instances to add virtual functions | |
3914 | * to a class. | |
3915 | */ | |
3916 | if (funcdecl.isVirtual()) | |
3917 | { | |
6384eff5 | 3918 | if (auto ti = parent.isTemplateInstance()) |
5fee5ec3 IB |
3919 | { |
3920 | // Take care of nested templates | |
3921 | while (1) | |
3922 | { | |
3923 | TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); | |
3924 | if (!ti2) | |
3925 | break; | |
3926 | ti = ti2; | |
3927 | } | |
3928 | ||
3929 | // If it's a member template | |
3930 | ClassDeclaration cd = ti.tempdecl.isClassMember(); | |
3931 | if (cd) | |
3932 | { | |
3933 | funcdecl.error("cannot use template to add virtual function to class `%s`", cd.toChars()); | |
3934 | } | |
3935 | } | |
3936 | } | |
3937 | ||
235d5a96 | 3938 | funcdecl.checkMain(); // Check main() parameters and return type |
5fee5ec3 IB |
3939 | |
3940 | /* Purity and safety can be inferred for some functions by examining | |
3941 | * the function body. | |
3942 | */ | |
3943 | if (funcdecl.canInferAttributes(sc)) | |
3944 | funcdecl.initInferAttributes(); | |
3945 | ||
5fee5ec3 IB |
3946 | funcdecl.semanticRun = PASS.semanticdone; |
3947 | ||
3948 | /* Save scope for possible later use (if we need the | |
3949 | * function internals) | |
3950 | */ | |
3951 | funcdecl._scope = sc.copy(); | |
3952 | funcdecl._scope.setNoFree(); | |
3953 | ||
3954 | __gshared bool printedMain = false; // semantic might run more than once | |
3955 | if (global.params.verbose && !printedMain) | |
3956 | { | |
3957 | const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null; | |
3958 | Module mod = sc._module; | |
3959 | ||
3960 | if (type && mod) | |
3961 | { | |
3962 | printedMain = true; | |
3963 | auto name = mod.srcfile.toChars(); | |
3964 | auto path = FileName.searchPath(global.path, name, true); | |
3965 | message("entry %-10s\t%s", type, path ? path : name); | |
3966 | } | |
3967 | } | |
3968 | ||
0fb57034 IB |
3969 | if (funcdecl.fbody && sc._module.isRoot() && |
3970 | (funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain())) | |
3971 | global.hasMainFunction = true; | |
3972 | ||
5fee5ec3 IB |
3973 | if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot()) |
3974 | { | |
3975 | // check if `_d_cmain` is defined | |
3976 | bool cmainTemplateExists() | |
3977 | { | |
3978 | auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null); | |
3979 | if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object)) | |
3980 | if (moduleSymbol.search(funcdecl.loc, Id.CMain)) | |
3981 | return true; | |
3982 | ||
3983 | return false; | |
3984 | } | |
3985 | ||
3986 | // Only mixin `_d_cmain` if it is defined | |
3987 | if (cmainTemplateExists()) | |
3988 | { | |
3989 | // add `mixin _d_cmain!();` to the declaring module | |
3990 | auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain); | |
3991 | auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null); | |
3992 | sc._module.members.push(tm); | |
3993 | } | |
3994 | } | |
3995 | ||
3996 | assert(funcdecl.type.ty != Terror || funcdecl.errors); | |
3997 | ||
3998 | // semantic for parameters' UDAs | |
3999 | foreach (i, param; f.parameterList) | |
4000 | { | |
4001 | if (param && param.userAttribDecl) | |
4002 | param.userAttribDecl.dsymbolSemantic(sc); | |
4003 | } | |
4004 | } | |
4005 | ||
4006 | /// Do the semantic analysis on the external interface to the function. | |
4007 | override void visit(FuncDeclaration funcdecl) | |
4008 | { | |
4009 | funcDeclarationSemantic(funcdecl); | |
4010 | } | |
4011 | ||
4012 | override void visit(CtorDeclaration ctd) | |
4013 | { | |
4014 | //printf("CtorDeclaration::semantic() %s\n", toChars()); | |
4015 | if (ctd.semanticRun >= PASS.semanticdone) | |
4016 | return; | |
4017 | if (ctd._scope) | |
4018 | { | |
4019 | sc = ctd._scope; | |
4020 | ctd._scope = null; | |
4021 | } | |
4022 | ||
4023 | ctd.parent = sc.parent; | |
4024 | Dsymbol p = ctd.toParentDecl(); | |
4025 | AggregateDeclaration ad = p.isAggregateDeclaration(); | |
4026 | if (!ad) | |
4027 | { | |
4028 | error(ctd.loc, "constructor can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); | |
4029 | ctd.type = Type.terror; | |
4030 | ctd.errors = true; | |
4031 | return; | |
4032 | } | |
4033 | ||
4034 | sc = sc.push(); | |
4035 | ||
4036 | if (sc.stc & STC.static_) | |
4037 | { | |
4038 | if (sc.stc & STC.shared_) | |
4039 | error(ctd.loc, "`shared static` has no effect on a constructor inside a `shared static` block. Use `shared static this()`"); | |
4040 | else | |
4041 | error(ctd.loc, "`static` has no effect on a constructor inside a `static` block. Use `static this()`"); | |
4042 | } | |
4043 | ||
4044 | sc.stc &= ~STC.static_; // not a static constructor | |
4045 | ||
4046 | funcDeclarationSemantic(ctd); | |
4047 | ||
4048 | sc.pop(); | |
4049 | ||
4050 | if (ctd.errors) | |
4051 | return; | |
4052 | ||
4053 | TypeFunction tf = ctd.type.toTypeFunction(); | |
b3f58f87 IB |
4054 | immutable dim = tf.parameterList.length; |
4055 | auto sd = ad.isStructDeclaration(); | |
5fee5ec3 IB |
4056 | |
4057 | /* See if it's the default constructor | |
4058 | * But, template constructor should not become a default constructor. | |
4059 | */ | |
4060 | if (ad && (!ctd.parent.isTemplateInstance() || ctd.parent.isTemplateMixin())) | |
4061 | { | |
5eb9927a | 4062 | if (!sd) |
5fee5ec3 | 4063 | { |
5eb9927a IB |
4064 | if (dim == 0 && tf.parameterList.varargs == VarArg.none) |
4065 | ad.defaultCtor = ctd; | |
4066 | return; | |
4067 | } | |
4068 | ||
4069 | if (dim == 0 && tf.parameterList.varargs == VarArg.none) // empty default ctor w/o any varargs | |
4070 | { | |
4071 | if (ctd.fbody || !(ctd.storage_class & STC.disable)) | |
5fee5ec3 | 4072 | { |
5eb9927a IB |
4073 | ctd.error("default constructor for structs only allowed " ~ |
4074 | "with `@disable`, no body, and no parameters"); | |
4075 | ctd.storage_class |= STC.disable; | |
4076 | ctd.fbody = null; | |
5fee5ec3 | 4077 | } |
5eb9927a IB |
4078 | sd.noDefaultCtor = true; |
4079 | } | |
4080 | else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor | |
4081 | { | |
4082 | } | |
4083 | else if (dim && tf.parameterList[0].defaultArg) | |
4084 | { | |
4085 | // if the first parameter has a default argument, then the rest does as well | |
4086 | if (ctd.storage_class & STC.disable) | |
5fee5ec3 | 4087 | { |
5eb9927a IB |
4088 | ctd.error("is marked `@disable`, so it cannot have default "~ |
4089 | "arguments for all parameters."); | |
4090 | errorSupplemental(ctd.loc, "Use `@disable this();` if you want to disable default initialization."); | |
5fee5ec3 | 4091 | } |
5eb9927a IB |
4092 | else |
4093 | ctd.error("all parameters have default arguments, "~ | |
4094 | "but structs cannot have default constructors."); | |
5fee5ec3 | 4095 | } |
5eb9927a | 4096 | else if ((dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) |
5fee5ec3 | 4097 | { |
5eb9927a IB |
4098 | //printf("tf: %s\n", tf.toChars()); |
4099 | auto param = tf.parameterList[0]; | |
4100 | if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) | |
4101 | { | |
4102 | //printf("copy constructor\n"); | |
4103 | ctd.isCpCtor = true; | |
4104 | } | |
5fee5ec3 IB |
4105 | } |
4106 | } | |
b3f58f87 IB |
4107 | // https://issues.dlang.org/show_bug.cgi?id=22593 |
4108 | else if (auto ti = ctd.parent.isTemplateInstance()) | |
4109 | { | |
5eb9927a IB |
4110 | if (!sd || !sd.hasCopyCtor || !(dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) |
4111 | return; | |
b3f58f87 | 4112 | |
5eb9927a IB |
4113 | auto param = tf.parameterList[0]; |
4114 | ||
4115 | // if the template instance introduces an rvalue constructor | |
4116 | // between the members of a struct declaration, we should check if a | |
4117 | // copy constructor exists and issue an error in that case. | |
4118 | if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) | |
4119 | { | |
4120 | .error(ctd.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars); | |
4121 | .errorSupplemental(ti.loc, "Template instance `%s` creates a rvalue constructor for `struct %s`", | |
4122 | ti.toChars(), sd.toChars()); | |
b3f58f87 IB |
4123 | } |
4124 | } | |
5fee5ec3 IB |
4125 | } |
4126 | ||
4127 | override void visit(PostBlitDeclaration pbd) | |
4128 | { | |
4129 | //printf("PostBlitDeclaration::semantic() %s\n", toChars()); | |
31350635 | 4130 | //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor); |
5fee5ec3 IB |
4131 | //printf("stc = x%llx\n", sc.stc); |
4132 | if (pbd.semanticRun >= PASS.semanticdone) | |
4133 | return; | |
4134 | if (pbd._scope) | |
4135 | { | |
4136 | sc = pbd._scope; | |
4137 | pbd._scope = null; | |
4138 | } | |
4139 | ||
4140 | pbd.parent = sc.parent; | |
4141 | Dsymbol p = pbd.toParent2(); | |
4142 | StructDeclaration ad = p.isStructDeclaration(); | |
4143 | if (!ad) | |
4144 | { | |
4145 | error(pbd.loc, "postblit can only be a member of struct, not %s `%s`", p.kind(), p.toChars()); | |
4146 | pbd.type = Type.terror; | |
4147 | pbd.errors = true; | |
4148 | return; | |
4149 | } | |
4150 | if (pbd.ident == Id.postblit && pbd.semanticRun < PASS.semantic) | |
4151 | ad.postblits.push(pbd); | |
4152 | if (!pbd.type) | |
4153 | pbd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, pbd.storage_class); | |
4154 | ||
4155 | sc = sc.push(); | |
4156 | sc.stc &= ~STC.static_; // not static | |
4157 | sc.linkage = LINK.d; | |
4158 | ||
4159 | funcDeclarationSemantic(pbd); | |
4160 | ||
4161 | sc.pop(); | |
4162 | } | |
4163 | ||
4164 | override void visit(DtorDeclaration dd) | |
4165 | { | |
4166 | //printf("DtorDeclaration::semantic() %s\n", toChars()); | |
31350635 | 4167 | //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor); |
5fee5ec3 IB |
4168 | if (dd.semanticRun >= PASS.semanticdone) |
4169 | return; | |
4170 | if (dd._scope) | |
4171 | { | |
4172 | sc = dd._scope; | |
4173 | dd._scope = null; | |
4174 | } | |
4175 | ||
4176 | dd.parent = sc.parent; | |
4177 | Dsymbol p = dd.toParent2(); | |
4178 | AggregateDeclaration ad = p.isAggregateDeclaration(); | |
4179 | if (!ad) | |
4180 | { | |
4181 | error(dd.loc, "destructor can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); | |
4182 | dd.type = Type.terror; | |
4183 | dd.errors = true; | |
4184 | return; | |
4185 | } | |
c8dfa79c IB |
4186 | |
4187 | if (ad.isClassDeclaration() && ad.classKind == ClassKind.d) | |
4188 | { | |
4189 | // Class destructors are implicitly `scope` | |
4190 | dd.storage_class |= STC.scope_; | |
4191 | } | |
4192 | ||
5fee5ec3 | 4193 | if (dd.ident == Id.dtor && dd.semanticRun < PASS.semantic) |
0fb57034 | 4194 | ad.userDtors.push(dd); |
5fee5ec3 IB |
4195 | if (!dd.type) |
4196 | { | |
4197 | dd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, dd.storage_class); | |
4198 | if (ad.classKind == ClassKind.cpp && dd.ident == Id.dtor) | |
4199 | { | |
4200 | if (auto cldec = ad.isClassDeclaration()) | |
4201 | { | |
4202 | assert (cldec.cppDtorVtblIndex == -1); // double-call check already by dd.type | |
4203 | if (cldec.baseClass && cldec.baseClass.cppDtorVtblIndex != -1) | |
4204 | { | |
4205 | // override the base virtual | |
4206 | cldec.cppDtorVtblIndex = cldec.baseClass.cppDtorVtblIndex; | |
4207 | } | |
4208 | else if (!dd.isFinal()) | |
4209 | { | |
4210 | // reserve the dtor slot for the destructor (which we'll create later) | |
4211 | cldec.cppDtorVtblIndex = cast(int)cldec.vtbl.dim; | |
4212 | cldec.vtbl.push(dd); | |
4213 | if (target.cpp.twoDtorInVtable) | |
4214 | cldec.vtbl.push(dd); // deleting destructor uses a second slot | |
4215 | } | |
4216 | } | |
4217 | } | |
4218 | } | |
4219 | ||
4220 | sc = sc.push(); | |
4221 | sc.stc &= ~STC.static_; // not a static destructor | |
4222 | if (sc.linkage != LINK.cpp) | |
4223 | sc.linkage = LINK.d; | |
4224 | ||
4225 | funcDeclarationSemantic(dd); | |
4226 | ||
4227 | sc.pop(); | |
4228 | } | |
4229 | ||
4230 | override void visit(StaticCtorDeclaration scd) | |
4231 | { | |
4232 | //printf("StaticCtorDeclaration::semantic()\n"); | |
4233 | if (scd.semanticRun >= PASS.semanticdone) | |
4234 | return; | |
4235 | if (scd._scope) | |
4236 | { | |
4237 | sc = scd._scope; | |
4238 | scd._scope = null; | |
4239 | } | |
4240 | ||
4241 | scd.parent = sc.parent; | |
4242 | Dsymbol p = scd.parent.pastMixin(); | |
4243 | if (!p.isScopeDsymbol()) | |
4244 | { | |
4245 | const(char)* s = (scd.isSharedStaticCtorDeclaration() ? "shared " : ""); | |
4246 | error(scd.loc, "`%sstatic` constructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars()); | |
4247 | scd.type = Type.terror; | |
4248 | scd.errors = true; | |
4249 | return; | |
4250 | } | |
4251 | if (!scd.type) | |
4252 | scd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, scd.storage_class); | |
4253 | ||
4254 | /* If the static ctor appears within a template instantiation, | |
4255 | * it could get called multiple times by the module constructors | |
4256 | * for different modules. Thus, protect it with a gate. | |
4257 | */ | |
4258 | if (scd.isInstantiated() && scd.semanticRun < PASS.semantic) | |
4259 | { | |
fbdaa581 IB |
4260 | /* Add this prefix to the constructor: |
4261 | * ``` | |
4262 | * static int gate; | |
4263 | * if (++gate != 1) return; | |
4264 | * ``` | |
4265 | * or, for shared constructor: | |
4266 | * ``` | |
4267 | * shared int gate; | |
4268 | * if (core.atomic.atomicOp!"+="(gate, 1) != 1) return; | |
4269 | * ``` | |
5fee5ec3 | 4270 | */ |
fbdaa581 | 4271 | const bool isShared = !!scd.isSharedStaticCtorDeclaration(); |
5fee5ec3 | 4272 | auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null); |
fbdaa581 | 4273 | v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0); |
5fee5ec3 IB |
4274 | |
4275 | auto sa = new Statements(); | |
4276 | Statement s = new ExpStatement(Loc.initial, v); | |
4277 | sa.push(s); | |
4278 | ||
fbdaa581 IB |
4279 | Expression e; |
4280 | if (isShared) | |
4281 | { | |
4282 | e = doAtomicOp("+=", v.ident, IntegerExp.literal!(1)); | |
4283 | if (e is null) | |
4284 | { | |
4285 | scd.error("shared static constructor within a template require `core.atomic : atomicOp` to be present"); | |
4286 | return; | |
4287 | } | |
4288 | } | |
4289 | else | |
4290 | { | |
4291 | e = new AddAssignExp( | |
4292 | Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!1); | |
4293 | } | |
4294 | ||
9c7d5e88 | 4295 | e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!1); |
5fee5ec3 IB |
4296 | s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial); |
4297 | ||
4298 | sa.push(s); | |
4299 | if (scd.fbody) | |
4300 | sa.push(scd.fbody); | |
4301 | ||
4302 | scd.fbody = new CompoundStatement(Loc.initial, sa); | |
4303 | } | |
4304 | ||
4305 | const LINK save = sc.linkage; | |
4306 | if (save != LINK.d) | |
4307 | { | |
4308 | const(char)* s = (scd.isSharedStaticCtorDeclaration() ? "shared " : ""); | |
4309 | deprecation(scd.loc, "`%sstatic` constructor can only be of D linkage", s); | |
4310 | // Just correct it | |
4311 | sc.linkage = LINK.d; | |
4312 | } | |
4313 | funcDeclarationSemantic(scd); | |
4314 | sc.linkage = save; | |
4315 | ||
4316 | // We're going to need ModuleInfo | |
4317 | Module m = scd.getModule(); | |
4318 | if (!m) | |
4319 | m = sc._module; | |
4320 | if (m) | |
4321 | { | |
4322 | m.needmoduleinfo = 1; | |
4323 | //printf("module1 %s needs moduleinfo\n", m.toChars()); | |
4324 | } | |
4325 | } | |
4326 | ||
4327 | override void visit(StaticDtorDeclaration sdd) | |
4328 | { | |
4329 | if (sdd.semanticRun >= PASS.semanticdone) | |
4330 | return; | |
4331 | if (sdd._scope) | |
4332 | { | |
4333 | sc = sdd._scope; | |
4334 | sdd._scope = null; | |
4335 | } | |
4336 | ||
4337 | sdd.parent = sc.parent; | |
4338 | Dsymbol p = sdd.parent.pastMixin(); | |
4339 | if (!p.isScopeDsymbol()) | |
4340 | { | |
4341 | const(char)* s = (sdd.isSharedStaticDtorDeclaration() ? "shared " : ""); | |
4342 | error(sdd.loc, "`%sstatic` destructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars()); | |
4343 | sdd.type = Type.terror; | |
4344 | sdd.errors = true; | |
4345 | return; | |
4346 | } | |
4347 | if (!sdd.type) | |
4348 | sdd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, sdd.storage_class); | |
4349 | ||
4350 | /* If the static ctor appears within a template instantiation, | |
4351 | * it could get called multiple times by the module constructors | |
4352 | * for different modules. Thus, protect it with a gate. | |
4353 | */ | |
4354 | if (sdd.isInstantiated() && sdd.semanticRun < PASS.semantic) | |
4355 | { | |
fbdaa581 IB |
4356 | /* Add this prefix to the constructor: |
4357 | * ``` | |
4358 | * static int gate; | |
4359 | * if (--gate != 0) return; | |
4360 | * ``` | |
4361 | * or, for shared constructor: | |
4362 | * ``` | |
4363 | * shared int gate; | |
4364 | * if (core.atomic.atomicOp!"-="(gate, 1) != 0) return; | |
4365 | * ``` | |
5fee5ec3 | 4366 | */ |
fbdaa581 | 4367 | const bool isShared = !!sdd.isSharedStaticDtorDeclaration(); |
5fee5ec3 | 4368 | auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null); |
fbdaa581 | 4369 | v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0); |
5fee5ec3 IB |
4370 | |
4371 | auto sa = new Statements(); | |
4372 | Statement s = new ExpStatement(Loc.initial, v); | |
4373 | sa.push(s); | |
4374 | ||
fbdaa581 IB |
4375 | Expression e; |
4376 | if (isShared) | |
4377 | { | |
4378 | e = doAtomicOp("-=", v.ident, IntegerExp.literal!(1)); | |
4379 | if (e is null) | |
4380 | { | |
4381 | sdd.error("shared static destructo within a template require `core.atomic : atomicOp` to be present"); | |
4382 | return; | |
4383 | } | |
4384 | } | |
4385 | else | |
4386 | { | |
4387 | e = new AddAssignExp( | |
4388 | Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!(-1)); | |
4389 | } | |
4390 | ||
9c7d5e88 | 4391 | e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!0); |
5fee5ec3 IB |
4392 | s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial); |
4393 | ||
4394 | sa.push(s); | |
4395 | if (sdd.fbody) | |
4396 | sa.push(sdd.fbody); | |
4397 | ||
4398 | sdd.fbody = new CompoundStatement(Loc.initial, sa); | |
4399 | ||
4400 | sdd.vgate = v; | |
4401 | } | |
4402 | ||
4403 | const LINK save = sc.linkage; | |
4404 | if (save != LINK.d) | |
4405 | { | |
4406 | const(char)* s = (sdd.isSharedStaticDtorDeclaration() ? "shared " : ""); | |
4407 | deprecation(sdd.loc, "`%sstatic` destructor can only be of D linkage", s); | |
4408 | // Just correct it | |
4409 | sc.linkage = LINK.d; | |
4410 | } | |
4411 | funcDeclarationSemantic(sdd); | |
4412 | sc.linkage = save; | |
4413 | ||
4414 | // We're going to need ModuleInfo | |
4415 | Module m = sdd.getModule(); | |
4416 | if (!m) | |
4417 | m = sc._module; | |
4418 | if (m) | |
4419 | { | |
4420 | m.needmoduleinfo = 1; | |
4421 | //printf("module2 %s needs moduleinfo\n", m.toChars()); | |
4422 | } | |
4423 | } | |
4424 | ||
4425 | override void visit(InvariantDeclaration invd) | |
4426 | { | |
4427 | if (invd.semanticRun >= PASS.semanticdone) | |
4428 | return; | |
4429 | if (invd._scope) | |
4430 | { | |
4431 | sc = invd._scope; | |
4432 | invd._scope = null; | |
4433 | } | |
4434 | ||
4435 | invd.parent = sc.parent; | |
4436 | Dsymbol p = invd.parent.pastMixin(); | |
4437 | AggregateDeclaration ad = p.isAggregateDeclaration(); | |
4438 | if (!ad) | |
4439 | { | |
4440 | error(invd.loc, "`invariant` can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); | |
4441 | invd.type = Type.terror; | |
4442 | invd.errors = true; | |
4443 | return; | |
4444 | } | |
4445 | if (invd.ident != Id.classInvariant && | |
4446 | invd.semanticRun < PASS.semantic && | |
4447 | !ad.isUnionDeclaration() // users are on their own with union fields | |
4448 | ) | |
b6df1132 IB |
4449 | { |
4450 | invd.fixupInvariantIdent(ad.invs.length); | |
5fee5ec3 | 4451 | ad.invs.push(invd); |
b6df1132 | 4452 | } |
5fee5ec3 IB |
4453 | if (!invd.type) |
4454 | invd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, invd.storage_class); | |
4455 | ||
4456 | sc = sc.push(); | |
4457 | sc.stc &= ~STC.static_; // not a static invariant | |
4458 | sc.stc |= STC.const_; // invariant() is always const | |
4459 | sc.flags = (sc.flags & ~SCOPE.contract) | SCOPE.invariant_; | |
4460 | sc.linkage = LINK.d; | |
4461 | ||
4462 | funcDeclarationSemantic(invd); | |
4463 | ||
4464 | sc.pop(); | |
4465 | } | |
4466 | ||
4467 | override void visit(UnitTestDeclaration utd) | |
4468 | { | |
4469 | if (utd.semanticRun >= PASS.semanticdone) | |
4470 | return; | |
4471 | if (utd._scope) | |
4472 | { | |
4473 | sc = utd._scope; | |
4474 | utd._scope = null; | |
4475 | } | |
4476 | ||
4477 | utd.visibility = sc.visibility; | |
4478 | ||
4479 | utd.parent = sc.parent; | |
4480 | Dsymbol p = utd.parent.pastMixin(); | |
4481 | if (!p.isScopeDsymbol()) | |
4482 | { | |
4483 | error(utd.loc, "`unittest` can only be a member of module/aggregate/template, not %s `%s`", p.kind(), p.toChars()); | |
4484 | utd.type = Type.terror; | |
4485 | utd.errors = true; | |
4486 | return; | |
4487 | } | |
4488 | ||
4489 | if (global.params.useUnitTests) | |
4490 | { | |
4491 | if (!utd.type) | |
4492 | utd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, utd.storage_class); | |
4493 | Scope* sc2 = sc.push(); | |
4494 | sc2.linkage = LINK.d; | |
4495 | funcDeclarationSemantic(utd); | |
4496 | sc2.pop(); | |
4497 | } | |
4498 | ||
4499 | version (none) | |
4500 | { | |
4501 | // We're going to need ModuleInfo even if the unit tests are not | |
4502 | // compiled in, because other modules may import this module and refer | |
4503 | // to this ModuleInfo. | |
4504 | // (This doesn't make sense to me?) | |
4505 | Module m = utd.getModule(); | |
4506 | if (!m) | |
4507 | m = sc._module; | |
4508 | if (m) | |
4509 | { | |
4510 | //printf("module3 %s needs moduleinfo\n", m.toChars()); | |
4511 | m.needmoduleinfo = 1; | |
4512 | } | |
4513 | } | |
4514 | } | |
4515 | ||
4516 | override void visit(NewDeclaration nd) | |
4517 | { | |
4518 | //printf("NewDeclaration::semantic()\n"); | |
4519 | if (nd.semanticRun >= PASS.semanticdone) | |
4520 | return; | |
4521 | if (!nd.type) | |
4522 | nd.type = new TypeFunction(ParameterList(), Type.tvoid.pointerTo(), LINK.d, nd.storage_class); | |
4523 | ||
4524 | funcDeclarationSemantic(nd); | |
4525 | } | |
4526 | ||
4527 | override void visit(StructDeclaration sd) | |
4528 | { | |
4529 | //printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); | |
4530 | ||
4531 | //static int count; if (++count == 20) assert(0); | |
4532 | ||
4533 | if (sd.semanticRun >= PASS.semanticdone) | |
4534 | return; | |
4535 | int errors = global.errors; | |
4536 | ||
6384eff5 | 4537 | //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); |
5fee5ec3 IB |
4538 | Scope* scx = null; |
4539 | if (sd._scope) | |
4540 | { | |
4541 | sc = sd._scope; | |
4542 | scx = sd._scope; // save so we don't make redundant copies | |
4543 | sd._scope = null; | |
4544 | } | |
4545 | ||
4546 | if (!sd.parent) | |
4547 | { | |
4548 | assert(sc.parent && sc.func); | |
4549 | sd.parent = sc.parent; | |
4550 | } | |
4551 | assert(sd.parent && !sd.isAnonymous()); | |
4552 | ||
4553 | if (sd.errors) | |
4554 | sd.type = Type.terror; | |
235d5a96 | 4555 | if (sd.semanticRun == PASS.initial) |
5fee5ec3 IB |
4556 | sd.type = sd.type.addSTC(sc.stc | sd.storage_class); |
4557 | sd.type = sd.type.typeSemantic(sd.loc, sc); | |
4558 | if (auto ts = sd.type.isTypeStruct()) | |
4559 | if (ts.sym != sd) | |
4560 | { | |
4561 | auto ti = ts.sym.isInstantiated(); | |
4562 | if (ti && isError(ti)) | |
4563 | ts.sym = sd; | |
4564 | } | |
4565 | ||
4566 | // Ungag errors when not speculative | |
4567 | Ungag ungag = sd.ungagSpeculative(); | |
4568 | ||
235d5a96 | 4569 | if (sd.semanticRun == PASS.initial) |
5fee5ec3 IB |
4570 | { |
4571 | sd.visibility = sc.visibility; | |
4572 | ||
4573 | sd.alignment = sc.alignment(); | |
4574 | ||
4575 | sd.storage_class |= sc.stc; | |
4576 | if (sd.storage_class & STC.abstract_) | |
4577 | sd.error("structs, unions cannot be `abstract`"); | |
4578 | ||
4579 | sd.userAttribDecl = sc.userAttribDecl; | |
4580 | ||
4581 | if (sc.linkage == LINK.cpp) | |
4582 | sd.classKind = ClassKind.cpp; | |
4583 | else if (sc.linkage == LINK.c) | |
4584 | sd.classKind = ClassKind.c; | |
4585 | sd.cppnamespace = sc.namespace; | |
4586 | sd.cppmangle = sc.cppmangle; | |
4587 | } | |
4588 | else if (sd.symtab && !scx) | |
4589 | return; | |
4590 | ||
4591 | sd.semanticRun = PASS.semantic; | |
4592 | UserAttributeDeclaration.checkGNUABITag(sd, sc.linkage); | |
4593 | ||
4594 | if (!sd.members) // if opaque declaration | |
4595 | { | |
4596 | sd.semanticRun = PASS.semanticdone; | |
4597 | return; | |
4598 | } | |
4599 | if (!sd.symtab) | |
4600 | { | |
4601 | sd.symtab = new DsymbolTable(); | |
4602 | ||
4603 | sd.members.foreachDsymbol( s => s.addMember(sc, sd) ); | |
4604 | } | |
4605 | ||
4606 | auto sc2 = sd.newScope(sc); | |
4607 | ||
4608 | /* Set scope so if there are forward references, we still might be able to | |
4609 | * resolve individual members like enums. | |
4610 | */ | |
4611 | sd.members.foreachDsymbol( s => s.setScope(sc2) ); | |
4612 | sd.members.foreachDsymbol( s => s.importAll(sc2) ); | |
4613 | sd.members.foreachDsymbol( (s) { s.dsymbolSemantic(sc2); sd.errors |= s.errors; } ); | |
4614 | ||
4615 | if (sd.errors) | |
4616 | sd.type = Type.terror; | |
4617 | ||
4618 | if (!sd.determineFields()) | |
4619 | { | |
4620 | if (sd.type.ty != Terror) | |
4621 | { | |
4622 | sd.error(sd.loc, "circular or forward reference"); | |
4623 | sd.errors = true; | |
4624 | sd.type = Type.terror; | |
4625 | } | |
4626 | ||
4627 | sc2.pop(); | |
4628 | sd.semanticRun = PASS.semanticdone; | |
4629 | return; | |
4630 | } | |
4631 | /* Following special member functions creation needs semantic analysis | |
4632 | * completion of sub-structs in each field types. For example, buildDtor | |
4633 | * needs to check existence of elaborate dtor in type of each fields. | |
4634 | * See the case in compilable/test14838.d | |
4635 | */ | |
4636 | foreach (v; sd.fields) | |
4637 | { | |
4638 | Type tb = v.type.baseElemOf(); | |
4639 | if (tb.ty != Tstruct) | |
4640 | continue; | |
4641 | auto sdec = (cast(TypeStruct)tb).sym; | |
4642 | if (sdec.semanticRun >= PASS.semanticdone) | |
4643 | continue; | |
4644 | ||
4645 | sc2.pop(); | |
4646 | ||
4647 | //printf("\tdeferring %s\n", toChars()); | |
4648 | return deferDsymbolSemantic(sd, scx); | |
4649 | } | |
4650 | ||
4651 | /* Look for special member functions. | |
4652 | */ | |
4653 | sd.disableNew = sd.search(Loc.initial, Id.classNew) !is null; | |
4654 | ||
4655 | // Look for the constructor | |
4656 | sd.ctor = sd.searchCtor(); | |
4657 | ||
0fb57034 IB |
4658 | buildDtors(sd, sc2); |
4659 | ||
5fee5ec3 IB |
4660 | sd.hasCopyCtor = buildCopyCtor(sd, sc2); |
4661 | sd.postblit = buildPostBlit(sd, sc2); | |
4662 | ||
4663 | buildOpAssign(sd, sc2); | |
4664 | buildOpEquals(sd, sc2); | |
4665 | ||
ae56e2da IB |
4666 | if (!(sc2.flags & SCOPE.Cfile) && |
4667 | global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo | |
5fee5ec3 IB |
4668 | { |
4669 | sd.xeq = buildXopEquals(sd, sc2); | |
4670 | sd.xcmp = buildXopCmp(sd, sc2); | |
4671 | sd.xhash = buildXtoHash(sd, sc2); | |
4672 | } | |
4673 | ||
4674 | sd.inv = buildInv(sd, sc2); | |
4675 | ||
5fee5ec3 IB |
4676 | sd.semanticRun = PASS.semanticdone; |
4677 | //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd.toChars()); | |
4678 | ||
4679 | sc2.pop(); | |
4680 | ||
4681 | if (sd.ctor) | |
4682 | { | |
4683 | Dsymbol scall = sd.search(Loc.initial, Id.call); | |
4684 | if (scall) | |
4685 | { | |
4686 | uint xerrors = global.startGagging(); | |
4687 | sc = sc.push(); | |
4688 | sc.tinst = null; | |
4689 | sc.minst = null; | |
4690 | auto fcall = resolveFuncCall(sd.loc, sc, scall, null, null, null, FuncResolveFlag.quiet); | |
4691 | sc = sc.pop(); | |
4692 | global.endGagging(xerrors); | |
4693 | ||
4694 | if (fcall && fcall.isStatic()) | |
4695 | { | |
4696 | sd.error(fcall.loc, "`static opCall` is hidden by constructors and can never be called"); | |
4697 | errorSupplemental(fcall.loc, "Please use a factory method instead, or replace all constructors with `static opCall`."); | |
4698 | } | |
4699 | } | |
4700 | } | |
4701 | ||
4702 | if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd) | |
4703 | { | |
4704 | // https://issues.dlang.org/show_bug.cgi?id=19024 | |
4705 | StructDeclaration sym = (cast(TypeStruct)sd.type).sym; | |
4706 | version (none) | |
4707 | { | |
4708 | printf("this = %p %s\n", sd, sd.toChars()); | |
4709 | printf("type = %d sym = %p, %s\n", sd.type.ty, sym, sym.toPrettyChars()); | |
4710 | } | |
4711 | sd.error("already exists at %s. Perhaps in another function with the same name?", sym.loc.toChars()); | |
4712 | } | |
4713 | ||
4714 | if (global.errors != errors) | |
4715 | { | |
4716 | // The type is no good. | |
4717 | sd.type = Type.terror; | |
4718 | sd.errors = true; | |
4719 | if (sd.deferred) | |
4720 | sd.deferred.errors = true; | |
4721 | } | |
4722 | ||
4723 | if (sd.deferred && !global.gag) | |
4724 | { | |
4725 | sd.deferred.semantic2(sc); | |
4726 | sd.deferred.semantic3(sc); | |
4727 | } | |
7e287503 IB |
4728 | |
4729 | // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint | |
4730 | // Deprecated in 2.100 | |
4731 | // Make an error in 2.110 | |
4732 | if (sd.storage_class & STC.scope_) | |
4733 | deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); | |
5fee5ec3 IB |
4734 | } |
4735 | ||
4736 | void interfaceSemantic(ClassDeclaration cd) | |
4737 | { | |
4738 | cd.vtblInterfaces = new BaseClasses(); | |
4739 | cd.vtblInterfaces.reserve(cd.interfaces.length); | |
4740 | foreach (b; cd.interfaces) | |
4741 | { | |
4742 | cd.vtblInterfaces.push(b); | |
4743 | b.copyBaseInterfaces(cd.vtblInterfaces); | |
4744 | } | |
4745 | } | |
4746 | ||
4747 | override void visit(ClassDeclaration cldec) | |
4748 | { | |
4749 | //printf("ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", cldec.toChars(), cldec.type, cldec.sizeok, this); | |
4750 | //printf("\tparent = %p, '%s'\n", sc.parent, sc.parent ? sc.parent.toChars() : ""); | |
4751 | //printf("sc.stc = %x\n", sc.stc); | |
4752 | ||
4753 | //{ static int n; if (++n == 20) *(char*)0=0; } | |
4754 | ||
4755 | if (cldec.semanticRun >= PASS.semanticdone) | |
4756 | return; | |
4757 | int errors = global.errors; | |
4758 | ||
4759 | //printf("+ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); | |
4760 | ||
4761 | Scope* scx = null; | |
4762 | if (cldec._scope) | |
4763 | { | |
4764 | sc = cldec._scope; | |
4765 | scx = cldec._scope; // save so we don't make redundant copies | |
4766 | cldec._scope = null; | |
4767 | } | |
4768 | ||
4769 | if (!cldec.parent) | |
4770 | { | |
4771 | assert(sc.parent); | |
4772 | cldec.parent = sc.parent; | |
4773 | } | |
4774 | ||
4775 | if (cldec.errors) | |
4776 | cldec.type = Type.terror; | |
235d5a96 | 4777 | if (cldec.semanticRun == PASS.initial) |
9c7d5e88 | 4778 | cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class); |
5fee5ec3 IB |
4779 | cldec.type = cldec.type.typeSemantic(cldec.loc, sc); |
4780 | if (auto tc = cldec.type.isTypeClass()) | |
4781 | if (tc.sym != cldec) | |
4782 | { | |
4783 | auto ti = tc.sym.isInstantiated(); | |
4784 | if (ti && isError(ti)) | |
4785 | tc.sym = cldec; | |
4786 | } | |
4787 | ||
4788 | // Ungag errors when not speculative | |
4789 | Ungag ungag = cldec.ungagSpeculative(); | |
4790 | ||
235d5a96 | 4791 | if (cldec.semanticRun == PASS.initial) |
5fee5ec3 IB |
4792 | { |
4793 | cldec.visibility = sc.visibility; | |
4794 | ||
4795 | cldec.storage_class |= sc.stc; | |
4796 | if (cldec.storage_class & STC.auto_) | |
4797 | cldec.error("storage class `auto` is invalid when declaring a class, did you mean to use `scope`?"); | |
4798 | if (cldec.storage_class & STC.scope_) | |
4799 | cldec.stack = true; | |
4800 | if (cldec.storage_class & STC.abstract_) | |
4801 | cldec.isabstract = ThreeState.yes; | |
4802 | ||
4803 | cldec.userAttribDecl = sc.userAttribDecl; | |
4804 | ||
4805 | if (sc.linkage == LINK.cpp) | |
4806 | cldec.classKind = ClassKind.cpp; | |
4807 | cldec.cppnamespace = sc.namespace; | |
4808 | cldec.cppmangle = sc.cppmangle; | |
4809 | if (sc.linkage == LINK.objc) | |
4810 | objc.setObjc(cldec); | |
4811 | } | |
4812 | else if (cldec.symtab && !scx) | |
4813 | { | |
4814 | return; | |
4815 | } | |
4816 | cldec.semanticRun = PASS.semantic; | |
4817 | UserAttributeDeclaration.checkGNUABITag(cldec, sc.linkage); | |
31350635 | 4818 | checkMustUseReserved(cldec); |
5fee5ec3 IB |
4819 | |
4820 | if (cldec.baseok < Baseok.done) | |
4821 | { | |
4822 | /* https://issues.dlang.org/show_bug.cgi?id=12078 | |
4823 | * https://issues.dlang.org/show_bug.cgi?id=12143 | |
4824 | * https://issues.dlang.org/show_bug.cgi?id=15733 | |
4825 | * While resolving base classes and interfaces, a base may refer | |
4826 | * the member of this derived class. In that time, if all bases of | |
4827 | * this class can be determined, we can go forward the semantc process | |
4828 | * beyond the Lancestorsdone. To do the recursive semantic analysis, | |
4829 | * temporarily set and unset `_scope` around exp(). | |
4830 | */ | |
4831 | T resolveBase(T)(lazy T exp) | |
4832 | { | |
4833 | if (!scx) | |
4834 | { | |
4835 | scx = sc.copy(); | |
4836 | scx.setNoFree(); | |
4837 | } | |
4838 | static if (!is(T == void)) | |
4839 | { | |
4840 | cldec._scope = scx; | |
4841 | auto r = exp(); | |
4842 | cldec._scope = null; | |
4843 | return r; | |
4844 | } | |
4845 | else | |
4846 | { | |
4847 | cldec._scope = scx; | |
4848 | exp(); | |
4849 | cldec._scope = null; | |
4850 | } | |
4851 | } | |
4852 | ||
4853 | cldec.baseok = Baseok.start; | |
4854 | ||
4855 | // Expand any tuples in baseclasses[] | |
4856 | for (size_t i = 0; i < cldec.baseclasses.dim;) | |
4857 | { | |
4858 | auto b = (*cldec.baseclasses)[i]; | |
4859 | b.type = resolveBase(b.type.typeSemantic(cldec.loc, sc)); | |
4860 | ||
4861 | Type tb = b.type.toBasetype(); | |
4862 | if (auto tup = tb.isTypeTuple()) | |
4863 | { | |
4864 | cldec.baseclasses.remove(i); | |
4865 | size_t dim = Parameter.dim(tup.arguments); | |
4866 | for (size_t j = 0; j < dim; j++) | |
4867 | { | |
4868 | Parameter arg = Parameter.getNth(tup.arguments, j); | |
4869 | b = new BaseClass(arg.type); | |
4870 | cldec.baseclasses.insert(i + j, b); | |
4871 | } | |
4872 | } | |
4873 | else | |
4874 | i++; | |
4875 | } | |
4876 | ||
4877 | if (cldec.baseok >= Baseok.done) | |
4878 | { | |
4879 | //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun); | |
4880 | if (cldec.semanticRun >= PASS.semanticdone) | |
4881 | return; | |
4882 | goto Lancestorsdone; | |
4883 | } | |
4884 | ||
4885 | // See if there's a base class as first in baseclasses[] | |
4886 | if (cldec.baseclasses.dim) | |
4887 | { | |
4888 | BaseClass* b = (*cldec.baseclasses)[0]; | |
4889 | Type tb = b.type.toBasetype(); | |
4890 | TypeClass tc = tb.isTypeClass(); | |
4891 | if (!tc) | |
4892 | { | |
4893 | if (b.type != Type.terror) | |
4894 | cldec.error("base type must be `class` or `interface`, not `%s`", b.type.toChars()); | |
4895 | cldec.baseclasses.remove(0); | |
4896 | goto L7; | |
4897 | } | |
4898 | if (tc.sym.isDeprecated()) | |
4899 | { | |
4900 | if (!cldec.isDeprecated()) | |
4901 | { | |
4902 | // Deriving from deprecated class makes this one deprecated too | |
4903 | cldec.setDeprecated(); | |
4904 | tc.checkDeprecated(cldec.loc, sc); | |
4905 | } | |
4906 | } | |
4907 | if (tc.sym.isInterfaceDeclaration()) | |
4908 | goto L7; | |
4909 | ||
4910 | for (ClassDeclaration cdb = tc.sym; cdb; cdb = cdb.baseClass) | |
4911 | { | |
4912 | if (cdb == cldec) | |
4913 | { | |
4914 | cldec.error("circular inheritance"); | |
4915 | cldec.baseclasses.remove(0); | |
4916 | goto L7; | |
4917 | } | |
4918 | } | |
4919 | ||
4920 | /* https://issues.dlang.org/show_bug.cgi?id=11034 | |
4921 | * Class inheritance hierarchy | |
4922 | * and instance size of each classes are orthogonal information. | |
4923 | * Therefore, even if tc.sym.sizeof == Sizeok.none, | |
4924 | * we need to set baseClass field for class covariance check. | |
4925 | */ | |
4926 | cldec.baseClass = tc.sym; | |
4927 | b.sym = cldec.baseClass; | |
4928 | ||
4929 | if (tc.sym.baseok < Baseok.done) | |
4930 | resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference | |
4931 | if (tc.sym.baseok < Baseok.done) | |
4932 | { | |
4933 | //printf("\ttry later, forward reference of base class %s\n", tc.sym.toChars()); | |
4934 | if (tc.sym._scope) | |
4935 | Module.addDeferredSemantic(tc.sym); | |
4936 | cldec.baseok = Baseok.none; | |
4937 | } | |
4938 | L7: | |
4939 | } | |
4940 | ||
4941 | // Treat the remaining entries in baseclasses as interfaces | |
4942 | // Check for errors, handle forward references | |
4943 | int multiClassError = cldec.baseClass is null ? 0 : 1; | |
4944 | ||
4945 | BCLoop: | |
4946 | for (size_t i = (cldec.baseClass ? 1 : 0); i < cldec.baseclasses.dim;) | |
4947 | { | |
4948 | BaseClass* b = (*cldec.baseclasses)[i]; | |
4949 | Type tb = b.type.toBasetype(); | |
4950 | TypeClass tc = tb.isTypeClass(); | |
4951 | if (!tc || !tc.sym.isInterfaceDeclaration()) | |
4952 | { | |
4953 | // It's a class | |
4954 | if (tc) | |
4955 | { | |
4956 | if (multiClassError == 0) | |
4957 | { | |
4958 | error(cldec.loc,"`%s`: base class must be specified first, " ~ | |
4959 | "before any interfaces.", cldec.toPrettyChars()); | |
4960 | multiClassError += 1; | |
4961 | } | |
4962 | else if (multiClassError >= 1) | |
4963 | { | |
4964 | if(multiClassError == 1) | |
4965 | error(cldec.loc,"`%s`: multiple class inheritance is not supported." ~ | |
4966 | " Use multiple interface inheritance and/or composition.", cldec.toPrettyChars()); | |
4967 | multiClassError += 1; | |
4968 | ||
4969 | if (tc.sym.fields.dim) | |
4970 | errorSupplemental(cldec.loc,"`%s` has fields, consider making it a member of `%s`", | |
4971 | b.type.toChars(), cldec.type.toChars()); | |
4972 | else | |
4973 | errorSupplemental(cldec.loc,"`%s` has no fields, consider making it an `interface`", | |
4974 | b.type.toChars()); | |
4975 | } | |
4976 | } | |
4977 | // It's something else: e.g. `int` in `class Foo : Bar, int { ... }` | |
4978 | else if (b.type != Type.terror) | |
4979 | { | |
4980 | error(cldec.loc,"`%s`: base type must be `interface`, not `%s`", | |
4981 | cldec.toPrettyChars(), b.type.toChars()); | |
4982 | } | |
4983 | cldec.baseclasses.remove(i); | |
4984 | continue; | |
4985 | } | |
4986 | ||
4987 | // Check for duplicate interfaces | |
4988 | for (size_t j = (cldec.baseClass ? 1 : 0); j < i; j++) | |
4989 | { | |
4990 | BaseClass* b2 = (*cldec.baseclasses)[j]; | |
4991 | if (b2.sym == tc.sym) | |
4992 | { | |
4993 | cldec.error("inherits from duplicate interface `%s`", b2.sym.toChars()); | |
4994 | cldec.baseclasses.remove(i); | |
4995 | continue BCLoop; | |
4996 | } | |
4997 | } | |
4998 | if (tc.sym.isDeprecated()) | |
4999 | { | |
5000 | if (!cldec.isDeprecated()) | |
5001 | { | |
5002 | // Deriving from deprecated class makes this one deprecated too | |
5003 | cldec.setDeprecated(); | |
5004 | tc.checkDeprecated(cldec.loc, sc); | |
5005 | } | |
5006 | } | |
5007 | ||
5008 | b.sym = tc.sym; | |
5009 | ||
5010 | if (tc.sym.baseok < Baseok.done) | |
5011 | resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference | |
5012 | if (tc.sym.baseok < Baseok.done) | |
5013 | { | |
5014 | //printf("\ttry later, forward reference of base %s\n", tc.sym.toChars()); | |
5015 | if (tc.sym._scope) | |
5016 | Module.addDeferredSemantic(tc.sym); | |
5017 | cldec.baseok = Baseok.none; | |
5018 | } | |
5019 | i++; | |
5020 | } | |
5021 | if (cldec.baseok == Baseok.none) | |
5022 | { | |
5023 | // Forward referencee of one or more bases, try again later | |
5024 | //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); | |
5025 | return deferDsymbolSemantic(cldec, scx); | |
5026 | } | |
5027 | cldec.baseok = Baseok.done; | |
5028 | ||
5029 | if (cldec.classKind == ClassKind.objc || (cldec.baseClass && cldec.baseClass.classKind == ClassKind.objc)) | |
5030 | cldec.classKind = ClassKind.objc; // Objective-C classes do not inherit from Object | |
5031 | ||
5032 | // If no base class, and this is not an Object, use Object as base class | |
5033 | if (!cldec.baseClass && cldec.ident != Id.Object && cldec.object && cldec.classKind == ClassKind.d) | |
5034 | { | |
5035 | void badObjectDotD() | |
5036 | { | |
5037 | cldec.error("missing or corrupt object.d"); | |
5038 | fatal(); | |
5039 | } | |
5040 | ||
5041 | if (!cldec.object || cldec.object.errors) | |
5042 | badObjectDotD(); | |
5043 | ||
5044 | Type t = cldec.object.type; | |
5045 | t = t.typeSemantic(cldec.loc, sc).toBasetype(); | |
5046 | if (t.ty == Terror) | |
5047 | badObjectDotD(); | |
5048 | TypeClass tc = t.isTypeClass(); | |
5049 | assert(tc); | |
5050 | ||
5051 | auto b = new BaseClass(tc); | |
5052 | cldec.baseclasses.shift(b); | |
5053 | ||
5054 | cldec.baseClass = tc.sym; | |
5055 | assert(!cldec.baseClass.isInterfaceDeclaration()); | |
5056 | b.sym = cldec.baseClass; | |
5057 | } | |
5058 | if (cldec.baseClass) | |
5059 | { | |
5060 | if (cldec.baseClass.storage_class & STC.final_) | |
5061 | cldec.error("cannot inherit from class `%s` because it is `final`", cldec.baseClass.toChars()); | |
5062 | ||
5063 | // Inherit properties from base class | |
5064 | if (cldec.baseClass.isCOMclass()) | |
5065 | cldec.com = true; | |
5066 | if (cldec.baseClass.isCPPclass()) | |
5067 | cldec.classKind = ClassKind.cpp; | |
ae56e2da IB |
5068 | if (cldec.classKind != cldec.baseClass.classKind) |
5069 | cldec.error("with %s linkage cannot inherit from class `%s` with %s linkage", | |
5070 | cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars()); | |
5071 | ||
5fee5ec3 IB |
5072 | if (cldec.baseClass.stack) |
5073 | cldec.stack = true; | |
5074 | cldec.enclosing = cldec.baseClass.enclosing; | |
5075 | cldec.storage_class |= cldec.baseClass.storage_class & STC.TYPECTOR; | |
5076 | } | |
5077 | ||
5078 | cldec.interfaces = cldec.baseclasses.tdata()[(cldec.baseClass ? 1 : 0) .. cldec.baseclasses.dim]; | |
5079 | foreach (b; cldec.interfaces) | |
5080 | { | |
5081 | // If this is an interface, and it derives from a COM interface, | |
5082 | // then this is a COM interface too. | |
5083 | if (b.sym.isCOMinterface()) | |
5084 | cldec.com = true; | |
5085 | if (cldec.classKind == ClassKind.cpp && !b.sym.isCPPinterface()) | |
5086 | { | |
5087 | error(cldec.loc, "C++ class `%s` cannot implement D interface `%s`", | |
5088 | cldec.toPrettyChars(), b.sym.toPrettyChars()); | |
5089 | } | |
5090 | } | |
5091 | interfaceSemantic(cldec); | |
5092 | } | |
5093 | Lancestorsdone: | |
5094 | //printf("\tClassDeclaration.dsymbolSemantic(%s) baseok = %d\n", toChars(), baseok); | |
5095 | ||
5096 | if (!cldec.members) // if opaque declaration | |
5097 | { | |
5098 | cldec.semanticRun = PASS.semanticdone; | |
5099 | return; | |
5100 | } | |
5101 | if (!cldec.symtab) | |
5102 | { | |
5103 | cldec.symtab = new DsymbolTable(); | |
5104 | ||
5105 | /* https://issues.dlang.org/show_bug.cgi?id=12152 | |
5106 | * The semantic analysis of base classes should be finished | |
5107 | * before the members semantic analysis of this class, in order to determine | |
5108 | * vtbl in this class. However if a base class refers the member of this class, | |
5109 | * it can be resolved as a normal forward reference. | |
5110 | * Call addMember() and setScope() to make this class members visible from the base classes. | |
5111 | */ | |
5112 | cldec.members.foreachDsymbol( s => s.addMember(sc, cldec) ); | |
5113 | ||
5114 | auto sc2 = cldec.newScope(sc); | |
5115 | ||
5116 | /* Set scope so if there are forward references, we still might be able to | |
5117 | * resolve individual members like enums. | |
5118 | */ | |
5119 | cldec.members.foreachDsymbol( s => s.setScope(sc2) ); | |
5120 | ||
5121 | sc2.pop(); | |
5122 | } | |
5123 | ||
5124 | for (size_t i = 0; i < cldec.baseclasses.dim; i++) | |
5125 | { | |
5126 | BaseClass* b = (*cldec.baseclasses)[i]; | |
5127 | Type tb = b.type.toBasetype(); | |
5128 | TypeClass tc = tb.isTypeClass(); | |
5129 | if (tc.sym.semanticRun < PASS.semanticdone) | |
5130 | { | |
5131 | // Forward referencee of one or more bases, try again later | |
5132 | if (tc.sym._scope) | |
5133 | Module.addDeferredSemantic(tc.sym); | |
5134 | //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); | |
5135 | return deferDsymbolSemantic(cldec, scx); | |
5136 | } | |
5137 | } | |
5138 | ||
5139 | if (cldec.baseok == Baseok.done) | |
5140 | { | |
5141 | cldec.baseok = Baseok.semanticdone; | |
5142 | objc.setMetaclass(cldec, sc); | |
5143 | ||
5144 | // initialize vtbl | |
5145 | if (cldec.baseClass) | |
5146 | { | |
5147 | if (cldec.classKind == ClassKind.cpp && cldec.baseClass.vtbl.dim == 0) | |
5148 | { | |
5149 | cldec.error("C++ base class `%s` needs at least one virtual function", cldec.baseClass.toChars()); | |
5150 | } | |
5151 | ||
5152 | // Copy vtbl[] from base class | |
5153 | cldec.vtbl.setDim(cldec.baseClass.vtbl.dim); | |
5154 | memcpy(cldec.vtbl.tdata(), cldec.baseClass.vtbl.tdata(), (void*).sizeof * cldec.vtbl.dim); | |
5155 | ||
5156 | cldec.vthis = cldec.baseClass.vthis; | |
5157 | cldec.vthis2 = cldec.baseClass.vthis2; | |
5158 | } | |
5159 | else | |
5160 | { | |
5161 | // No base class, so this is the root of the class hierarchy | |
5162 | cldec.vtbl.setDim(0); | |
5163 | if (cldec.vtblOffset()) | |
5164 | cldec.vtbl.push(cldec); // leave room for classinfo as first member | |
5165 | } | |
5166 | ||
5167 | /* If this is a nested class, add the hidden 'this' | |
5168 | * member which is a pointer to the enclosing scope. | |
5169 | */ | |
5170 | if (cldec.vthis) // if inheriting from nested class | |
5171 | { | |
5172 | // Use the base class's 'this' member | |
5173 | if (cldec.storage_class & STC.static_) | |
5174 | cldec.error("static class cannot inherit from nested class `%s`", cldec.baseClass.toChars()); | |
5175 | if (cldec.toParentLocal() != cldec.baseClass.toParentLocal() && | |
5176 | (!cldec.toParentLocal() || | |
5177 | !cldec.baseClass.toParentLocal().getType() || | |
5178 | !cldec.baseClass.toParentLocal().getType().isBaseOf(cldec.toParentLocal().getType(), null))) | |
5179 | { | |
5180 | if (cldec.toParentLocal()) | |
5181 | { | |
5182 | cldec.error("is nested within `%s`, but super class `%s` is nested within `%s`", | |
5183 | cldec.toParentLocal().toChars(), | |
5184 | cldec.baseClass.toChars(), | |
5185 | cldec.baseClass.toParentLocal().toChars()); | |
5186 | } | |
5187 | else | |
5188 | { | |
5189 | cldec.error("is not nested, but super class `%s` is nested within `%s`", | |
5190 | cldec.baseClass.toChars(), | |
5191 | cldec.baseClass.toParentLocal().toChars()); | |
5192 | } | |
5193 | cldec.enclosing = null; | |
5194 | } | |
5195 | if (cldec.vthis2) | |
5196 | { | |
5197 | if (cldec.toParent2() != cldec.baseClass.toParent2() && | |
5198 | (!cldec.toParent2() || | |
5199 | !cldec.baseClass.toParent2().getType() || | |
5200 | !cldec.baseClass.toParent2().getType().isBaseOf(cldec.toParent2().getType(), null))) | |
5201 | { | |
5202 | if (cldec.toParent2() && cldec.toParent2() != cldec.toParentLocal()) | |
5203 | { | |
5204 | cldec.error("needs the frame pointer of `%s`, but super class `%s` needs the frame pointer of `%s`", | |
5205 | cldec.toParent2().toChars(), | |
5206 | cldec.baseClass.toChars(), | |
5207 | cldec.baseClass.toParent2().toChars()); | |
5208 | } | |
5209 | else | |
5210 | { | |
5211 | cldec.error("doesn't need a frame pointer, but super class `%s` needs the frame pointer of `%s`", | |
5212 | cldec.baseClass.toChars(), | |
5213 | cldec.baseClass.toParent2().toChars()); | |
5214 | } | |
5215 | } | |
5216 | } | |
5217 | else | |
5218 | cldec.makeNested2(); | |
5219 | } | |
5220 | else | |
5221 | cldec.makeNested(); | |
5222 | } | |
5223 | ||
5224 | auto sc2 = cldec.newScope(sc); | |
5225 | ||
5226 | cldec.members.foreachDsymbol( s => s.importAll(sc2) ); | |
5227 | ||
5228 | // Note that members.dim can grow due to tuple expansion during semantic() | |
5229 | cldec.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) ); | |
5230 | ||
5231 | if (!cldec.determineFields()) | |
5232 | { | |
5233 | assert(cldec.type == Type.terror); | |
5234 | sc2.pop(); | |
5235 | return; | |
5236 | } | |
5237 | /* Following special member functions creation needs semantic analysis | |
5238 | * completion of sub-structs in each field types. | |
5239 | */ | |
5240 | foreach (v; cldec.fields) | |
5241 | { | |
5242 | Type tb = v.type.baseElemOf(); | |
5243 | if (tb.ty != Tstruct) | |
5244 | continue; | |
5245 | auto sd = (cast(TypeStruct)tb).sym; | |
5246 | if (sd.semanticRun >= PASS.semanticdone) | |
5247 | continue; | |
5248 | ||
5249 | sc2.pop(); | |
5250 | ||
5251 | //printf("\tdeferring %s\n", toChars()); | |
5252 | return deferDsymbolSemantic(cldec, scx); | |
5253 | } | |
5254 | ||
5255 | /* Look for special member functions. | |
5256 | * They must be in this class, not in a base class. | |
5257 | */ | |
5258 | // Can be in base class | |
5259 | cldec.disableNew = cldec.search(Loc.initial, Id.classNew) !is null; | |
5260 | ||
5261 | // Look for the constructor | |
5262 | cldec.ctor = cldec.searchCtor(); | |
5263 | ||
5264 | if (!cldec.ctor && cldec.noDefaultCtor) | |
5265 | { | |
5266 | // A class object is always created by constructor, so this check is legitimate. | |
5267 | foreach (v; cldec.fields) | |
5268 | { | |
5269 | if (v.storage_class & STC.nodefaultctor) | |
5270 | error(v.loc, "field `%s` must be initialized in constructor", v.toChars()); | |
5271 | } | |
5272 | } | |
5273 | ||
5274 | // If this class has no constructor, but base class has a default | |
5275 | // ctor, create a constructor: | |
5276 | // this() { } | |
5277 | if (!cldec.ctor && cldec.baseClass && cldec.baseClass.ctor) | |
5278 | { | |
5279 | auto fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type, null, FuncResolveFlag.quiet); | |
5280 | if (!fd) // try shared base ctor instead | |
5281 | fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type.sharedOf, null, FuncResolveFlag.quiet); | |
5282 | if (fd && !fd.errors) | |
5283 | { | |
5284 | //printf("Creating default this(){} for class %s\n", toChars()); | |
5285 | auto btf = fd.type.toTypeFunction(); | |
5286 | auto tf = new TypeFunction(ParameterList(), null, LINK.d, fd.storage_class); | |
5287 | tf.mod = btf.mod; | |
5288 | // Don't copy @safe, ... from the base class constructor and let it be inferred instead | |
5289 | // This is required if other lowerings add code to the generated constructor which | |
5290 | // is less strict (e.g. `preview=dtorfields` might introduce a call to a less qualified dtor) | |
5291 | ||
5292 | auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf); | |
5293 | ctor.storage_class |= STC.inference; | |
235d5a96 | 5294 | ctor.flags |= FUNCFLAG.generated; |
5fee5ec3 IB |
5295 | ctor.fbody = new CompoundStatement(Loc.initial, new Statements()); |
5296 | ||
5297 | cldec.members.push(ctor); | |
5298 | ctor.addMember(sc, cldec); | |
5299 | ctor.dsymbolSemantic(sc2); | |
5300 | ||
5301 | cldec.ctor = ctor; | |
5302 | cldec.defaultCtor = ctor; | |
5303 | } | |
5304 | else | |
5305 | { | |
5306 | cldec.error("cannot implicitly generate a default constructor when base class `%s` is missing a default constructor", | |
5307 | cldec.baseClass.toPrettyChars()); | |
5308 | } | |
5309 | } | |
5310 | ||
0fb57034 | 5311 | buildDtors(cldec, sc2); |
5fee5ec3 IB |
5312 | |
5313 | if (cldec.classKind == ClassKind.cpp && cldec.cppDtorVtblIndex != -1) | |
5314 | { | |
5315 | // now we've built the aggregate destructor, we'll make it virtual and assign it to the reserved vtable slot | |
5316 | cldec.dtor.vtblIndex = cldec.cppDtorVtblIndex; | |
5317 | cldec.vtbl[cldec.cppDtorVtblIndex] = cldec.dtor; | |
5318 | ||
5319 | if (target.cpp.twoDtorInVtable) | |
5320 | { | |
5321 | // TODO: create a C++ compatible deleting destructor (call out to `operator delete`) | |
5322 | // for the moment, we'll call the non-deleting destructor and leak | |
5323 | cldec.vtbl[cldec.cppDtorVtblIndex + 1] = cldec.dtor; | |
5324 | } | |
5325 | } | |
5326 | ||
5327 | if (auto f = hasIdentityOpAssign(cldec, sc2)) | |
5328 | { | |
5329 | if (!(f.storage_class & STC.disable)) | |
5330 | cldec.error(f.loc, "identity assignment operator overload is illegal"); | |
5331 | } | |
5332 | ||
5333 | cldec.inv = buildInv(cldec, sc2); | |
5334 | ||
5fee5ec3 IB |
5335 | cldec.semanticRun = PASS.semanticdone; |
5336 | //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); | |
5337 | ||
5338 | sc2.pop(); | |
5339 | ||
5340 | /* isAbstract() is undecidable in some cases because of circular dependencies. | |
5341 | * Now that semantic is finished, get a definitive result, and error if it is not the same. | |
5342 | */ | |
5343 | if (cldec.isabstract != ThreeState.none) // if evaluated it before completion | |
5344 | { | |
5345 | const isabstractsave = cldec.isabstract; | |
5346 | cldec.isabstract = ThreeState.none; | |
5347 | cldec.isAbstract(); // recalculate | |
5348 | if (cldec.isabstract != isabstractsave) | |
5349 | { | |
5350 | cldec.error("cannot infer `abstract` attribute due to circular dependencies"); | |
5351 | } | |
5352 | } | |
5353 | ||
5354 | if (cldec.type.ty == Tclass && (cast(TypeClass)cldec.type).sym != cldec) | |
5355 | { | |
5356 | // https://issues.dlang.org/show_bug.cgi?id=17492 | |
5357 | ClassDeclaration cd = (cast(TypeClass)cldec.type).sym; | |
5358 | version (none) | |
5359 | { | |
5360 | printf("this = %p %s\n", cldec, cldec.toPrettyChars()); | |
5361 | printf("type = %d sym = %p, %s\n", cldec.type.ty, cd, cd.toPrettyChars()); | |
5362 | } | |
5363 | cldec.error("already exists at %s. Perhaps in another function with the same name?", cd.loc.toChars()); | |
5364 | } | |
5365 | ||
5366 | if (global.errors != errors) | |
5367 | { | |
5368 | // The type is no good. | |
5369 | cldec.type = Type.terror; | |
5370 | cldec.errors = true; | |
5371 | if (cldec.deferred) | |
5372 | cldec.deferred.errors = true; | |
5373 | } | |
5374 | ||
5375 | // Verify fields of a synchronized class are not public | |
5376 | if (cldec.storage_class & STC.synchronized_) | |
5377 | { | |
5378 | foreach (vd; cldec.fields) | |
5379 | { | |
5380 | if (!vd.isThisDeclaration() && | |
5381 | vd.visible() >= Visibility(Visibility.Kind.public_)) | |
5382 | { | |
5383 | vd.error("Field members of a `synchronized` class cannot be `%s`", | |
5384 | visibilityToChars(vd.visible().kind)); | |
5385 | } | |
5386 | } | |
5387 | } | |
5388 | ||
5389 | if (cldec.deferred && !global.gag) | |
5390 | { | |
5391 | cldec.deferred.semantic2(sc); | |
5392 | cldec.deferred.semantic3(sc); | |
5393 | } | |
5394 | //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); | |
5395 | ||
7e287503 IB |
5396 | // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint |
5397 | // Deprecated in 2.100 | |
5398 | // Make an error in 2.110 | |
5fee5ec3 | 5399 | // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 |
7e287503 | 5400 | if (cldec.storage_class & STC.scope_) |
5fee5ec3 IB |
5401 | deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); |
5402 | } | |
5403 | ||
5404 | override void visit(InterfaceDeclaration idec) | |
5405 | { | |
5406 | /// Returns: `true` is this is an anonymous Objective-C metaclass | |
5407 | static bool isAnonymousMetaclass(InterfaceDeclaration idec) | |
5408 | { | |
5409 | return idec.classKind == ClassKind.objc && | |
5410 | idec.objc.isMeta && | |
5411 | idec.isAnonymous; | |
5412 | } | |
5413 | ||
5414 | //printf("InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); | |
5415 | if (idec.semanticRun >= PASS.semanticdone) | |
5416 | return; | |
5417 | int errors = global.errors; | |
5418 | ||
5419 | //printf("+InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); | |
5420 | ||
5421 | Scope* scx = null; | |
5422 | if (idec._scope) | |
5423 | { | |
5424 | sc = idec._scope; | |
5425 | scx = idec._scope; // save so we don't make redundant copies | |
5426 | idec._scope = null; | |
5427 | } | |
5428 | ||
5429 | if (!idec.parent) | |
5430 | { | |
5431 | assert(sc.parent && sc.func); | |
5432 | idec.parent = sc.parent; | |
5433 | } | |
5434 | // Objective-C metaclasses are anonymous | |
5435 | assert(idec.parent && !idec.isAnonymous || isAnonymousMetaclass(idec)); | |
5436 | ||
5437 | if (idec.errors) | |
5438 | idec.type = Type.terror; | |
5439 | idec.type = idec.type.typeSemantic(idec.loc, sc); | |
5440 | if (idec.type.ty == Tclass && (cast(TypeClass)idec.type).sym != idec) | |
5441 | { | |
5442 | auto ti = (cast(TypeClass)idec.type).sym.isInstantiated(); | |
5443 | if (ti && isError(ti)) | |
5444 | (cast(TypeClass)idec.type).sym = idec; | |
5445 | } | |
5446 | ||
5447 | // Ungag errors when not speculative | |
5448 | Ungag ungag = idec.ungagSpeculative(); | |
5449 | ||
235d5a96 | 5450 | if (idec.semanticRun == PASS.initial) |
5fee5ec3 IB |
5451 | { |
5452 | idec.visibility = sc.visibility; | |
5453 | ||
5454 | idec.storage_class |= sc.stc; | |
5455 | idec.userAttribDecl = sc.userAttribDecl; | |
5456 | } | |
5457 | else if (idec.symtab) | |
5458 | { | |
5459 | if (idec.sizeok == Sizeok.done || !scx) | |
5460 | { | |
5461 | idec.semanticRun = PASS.semanticdone; | |
5462 | return; | |
5463 | } | |
5464 | } | |
5465 | idec.semanticRun = PASS.semantic; | |
5466 | ||
5467 | if (idec.baseok < Baseok.done) | |
5468 | { | |
5469 | T resolveBase(T)(lazy T exp) | |
5470 | { | |
5471 | if (!scx) | |
5472 | { | |
5473 | scx = sc.copy(); | |
5474 | scx.setNoFree(); | |
5475 | } | |
5476 | static if (!is(T == void)) | |
5477 | { | |
5478 | idec._scope = scx; | |
5479 | auto r = exp(); | |
5480 | idec._scope = null; | |
5481 | return r; | |
5482 | } | |
5483 | else | |
5484 | { | |
5485 | idec._scope = scx; | |
5486 | exp(); | |
5487 | idec._scope = null; | |
5488 | } | |
5489 | } | |
5490 | ||
5491 | idec.baseok = Baseok.start; | |
5492 | ||
5493 | // Expand any tuples in baseclasses[] | |
5494 | for (size_t i = 0; i < idec.baseclasses.dim;) | |
5495 | { | |
5496 | auto b = (*idec.baseclasses)[i]; | |
5497 | b.type = resolveBase(b.type.typeSemantic(idec.loc, sc)); | |
5498 | ||
5499 | Type tb = b.type.toBasetype(); | |
5500 | if (auto tup = tb.isTypeTuple()) | |
5501 | { | |
5502 | idec.baseclasses.remove(i); | |
5503 | size_t dim = Parameter.dim(tup.arguments); | |
5504 | for (size_t j = 0; j < dim; j++) | |
5505 | { | |
5506 | Parameter arg = Parameter.getNth(tup.arguments, j); | |
5507 | b = new BaseClass(arg.type); | |
5508 | idec.baseclasses.insert(i + j, b); | |
5509 | } | |
5510 | } | |
5511 | else | |
5512 | i++; | |
5513 | } | |
5514 | ||
5515 | if (idec.baseok >= Baseok.done) | |
5516 | { | |
5517 | //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun); | |
5518 | if (idec.semanticRun >= PASS.semanticdone) | |
5519 | return; | |
5520 | goto Lancestorsdone; | |
5521 | } | |
5522 | ||
5523 | if (!idec.baseclasses.dim && sc.linkage == LINK.cpp) | |
5524 | idec.classKind = ClassKind.cpp; | |
5525 | idec.cppnamespace = sc.namespace; | |
5526 | UserAttributeDeclaration.checkGNUABITag(idec, sc.linkage); | |
31350635 | 5527 | checkMustUseReserved(idec); |
5fee5ec3 IB |
5528 | |
5529 | if (sc.linkage == LINK.objc) | |
5530 | objc.setObjc(idec); | |
5531 | ||
5532 | // Check for errors, handle forward references | |
5533 | BCLoop: | |
5534 | for (size_t i = 0; i < idec.baseclasses.dim;) | |
5535 | { | |
5536 | BaseClass* b = (*idec.baseclasses)[i]; | |
5537 | Type tb = b.type.toBasetype(); | |
5538 | TypeClass tc = (tb.ty == Tclass) ? cast(TypeClass)tb : null; | |
5539 | if (!tc || !tc.sym.isInterfaceDeclaration()) | |
5540 | { | |
5541 | if (b.type != Type.terror) | |
5542 | idec.error("base type must be `interface`, not `%s`", b.type.toChars()); | |
5543 | idec.baseclasses.remove(i); | |
5544 | continue; | |
5545 | } | |
5546 | ||
5547 | // Check for duplicate interfaces | |
5548 | for (size_t j = 0; j < i; j++) | |
5549 | { | |
5550 | BaseClass* b2 = (*idec.baseclasses)[j]; | |
5551 | if (b2.sym == tc.sym) | |
5552 | { | |
5553 | idec.error("inherits from duplicate interface `%s`", b2.sym.toChars()); | |
5554 | idec.baseclasses.remove(i); | |
5555 | continue BCLoop; | |
5556 | } | |
5557 | } | |
5558 | if (tc.sym == idec || idec.isBaseOf2(tc.sym)) | |
5559 | { | |
5560 | idec.error("circular inheritance of interface"); | |
5561 | idec.baseclasses.remove(i); | |
5562 | continue; | |
5563 | } | |
5564 | if (tc.sym.isDeprecated()) | |
5565 | { | |
5566 | if (!idec.isDeprecated()) | |
5567 | { | |
5568 | // Deriving from deprecated interface makes this one deprecated too | |
5569 | idec.setDeprecated(); | |
5570 | tc.checkDeprecated(idec.loc, sc); | |
5571 | } | |
5572 | } | |
5573 | ||
5574 | b.sym = tc.sym; | |
5575 | ||
5576 | if (tc.sym.baseok < Baseok.done) | |
5577 | resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference | |
5578 | if (tc.sym.baseok < Baseok.done) | |
5579 | { | |
5580 | //printf("\ttry later, forward reference of base %s\n", tc.sym.toChars()); | |
5581 | if (tc.sym._scope) | |
5582 | Module.addDeferredSemantic(tc.sym); | |
5583 | idec.baseok = Baseok.none; | |
5584 | } | |
5585 | i++; | |
5586 | } | |
5587 | if (idec.baseok == Baseok.none) | |
5588 | { | |
5589 | // Forward referencee of one or more bases, try again later | |
5590 | return deferDsymbolSemantic(idec, scx); | |
5591 | } | |
5592 | idec.baseok = Baseok.done; | |
5593 | ||
5594 | idec.interfaces = idec.baseclasses.tdata()[0 .. idec.baseclasses.dim]; | |
5595 | foreach (b; idec.interfaces) | |
5596 | { | |
5597 | // If this is an interface, and it derives from a COM interface, | |
5598 | // then this is a COM interface too. | |
5599 | if (b.sym.isCOMinterface()) | |
5600 | idec.com = true; | |
5601 | if (b.sym.isCPPinterface()) | |
5602 | idec.classKind = ClassKind.cpp; | |
5603 | } | |
5604 | ||
5605 | interfaceSemantic(idec); | |
5606 | } | |
5607 | Lancestorsdone: | |
5608 | ||
5609 | if (!idec.members) // if opaque declaration | |
5610 | { | |
5611 | idec.semanticRun = PASS.semanticdone; | |
5612 | return; | |
5613 | } | |
5614 | if (!idec.symtab) | |
5615 | idec.symtab = new DsymbolTable(); | |
5616 | ||
5617 | for (size_t i = 0; i < idec.baseclasses.dim; i++) | |
5618 | { | |
5619 | BaseClass* b = (*idec.baseclasses)[i]; | |
5620 | Type tb = b.type.toBasetype(); | |
5621 | TypeClass tc = tb.isTypeClass(); | |
5622 | if (tc.sym.semanticRun < PASS.semanticdone) | |
5623 | { | |
5624 | // Forward referencee of one or more bases, try again later | |
5625 | if (tc.sym._scope) | |
5626 | Module.addDeferredSemantic(tc.sym); | |
5627 | return deferDsymbolSemantic(idec, scx); | |
5628 | } | |
5629 | } | |
5630 | ||
5631 | if (idec.baseok == Baseok.done) | |
5632 | { | |
5633 | idec.baseok = Baseok.semanticdone; | |
5634 | objc.setMetaclass(idec, sc); | |
5635 | ||
5636 | // initialize vtbl | |
5637 | if (idec.vtblOffset()) | |
5638 | idec.vtbl.push(idec); // leave room at vtbl[0] for classinfo | |
5639 | ||
5640 | // Cat together the vtbl[]'s from base interfaces | |
5641 | foreach (i, b; idec.interfaces) | |
5642 | { | |
5643 | // Skip if b has already appeared | |
5644 | for (size_t k = 0; k < i; k++) | |
5645 | { | |
5646 | if (b == idec.interfaces[k]) | |
5647 | goto Lcontinue; | |
5648 | } | |
5649 | ||
5650 | // Copy vtbl[] from base class | |
5651 | if (b.sym.vtblOffset()) | |
5652 | { | |
5653 | size_t d = b.sym.vtbl.dim; | |
5654 | if (d > 1) | |
5655 | { | |
5656 | idec.vtbl.pushSlice(b.sym.vtbl[1 .. d]); | |
5657 | } | |
5658 | } | |
5659 | else | |
5660 | { | |
5661 | idec.vtbl.append(&b.sym.vtbl); | |
5662 | } | |
5663 | ||
5664 | Lcontinue: | |
5665 | } | |
5666 | } | |
5667 | ||
5668 | idec.members.foreachDsymbol( s => s.addMember(sc, idec) ); | |
5669 | ||
5670 | auto sc2 = idec.newScope(sc); | |
5671 | ||
5672 | /* Set scope so if there are forward references, we still might be able to | |
5673 | * resolve individual members like enums. | |
5674 | */ | |
5675 | idec.members.foreachDsymbol( s => s.setScope(sc2) ); | |
5676 | ||
5677 | idec.members.foreachDsymbol( s => s.importAll(sc2) ); | |
5678 | ||
5679 | idec.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) ); | |
5680 | ||
5fee5ec3 IB |
5681 | idec.semanticRun = PASS.semanticdone; |
5682 | //printf("-InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); | |
5683 | ||
5684 | sc2.pop(); | |
5685 | ||
5686 | if (global.errors != errors) | |
5687 | { | |
5688 | // The type is no good. | |
5689 | idec.type = Type.terror; | |
5690 | } | |
5691 | ||
5692 | version (none) | |
5693 | { | |
5694 | if (type.ty == Tclass && (cast(TypeClass)idec.type).sym != idec) | |
5695 | { | |
5696 | printf("this = %p %s\n", idec, idec.toChars()); | |
5697 | printf("type = %d sym = %p\n", idec.type.ty, (cast(TypeClass)idec.type).sym); | |
5698 | } | |
5699 | } | |
5700 | assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec); | |
5701 | ||
6384eff5 | 5702 | // @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint |
5fee5ec3 | 5703 | // Deprecated in 2.087 |
6384eff5 | 5704 | // Made an error in 2.100, but removal depends on `scope class` being removed too |
5fee5ec3 IB |
5705 | // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 |
5706 | if (idec.storage_class & STC.scope_) | |
6384eff5 | 5707 | error(idec.loc, "`scope` as a type constraint is obsolete. Use `scope` at the usage site."); |
5fee5ec3 IB |
5708 | } |
5709 | } | |
5710 | ||
5711 | /******************************************* | |
5712 | * Add members of EnumDeclaration to the symbol table(s). | |
5713 | * Params: | |
5714 | * ed = EnumDeclaration | |
5715 | * sc = context of `ed` | |
5716 | * sds = symbol table that `ed` resides in | |
5717 | */ | |
5718 | void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) | |
5719 | { | |
b6df1132 | 5720 | //printf("addEnumMembers(ed: %p)\n", ed); |
5fee5ec3 IB |
5721 | if (ed.added) |
5722 | return; | |
5723 | ed.added = true; | |
5724 | ||
5725 | if (!ed.members) | |
5726 | return; | |
5727 | ||
5728 | const bool isCEnum = (sc.flags & SCOPE.Cfile) != 0; // it's an ImportC enum | |
5729 | const bool isAnon = ed.isAnonymous(); | |
5730 | ||
5731 | if ((isCEnum || isAnon) && !sds.symtab) | |
5732 | sds.symtab = new DsymbolTable(); | |
5733 | ||
5734 | if ((isCEnum || !isAnon) && !ed.symtab) | |
5735 | ed.symtab = new DsymbolTable(); | |
5736 | ||
5737 | ed.members.foreachDsymbol( (s) | |
5738 | { | |
5739 | if (EnumMember em = s.isEnumMember()) | |
5740 | { | |
5741 | em.ed = ed; | |
5742 | if (isCEnum) | |
5743 | { | |
b6df1132 | 5744 | //printf("adding EnumMember %s to %p\n", em.toChars(), ed); |
5fee5ec3 IB |
5745 | em.addMember(sc, ed); // add em to ed's symbol table |
5746 | em.addMember(sc, sds); // add em to symbol table that ed is in | |
5747 | em.parent = ed; // restore it after previous addMember() changed it | |
5748 | } | |
5749 | else | |
5750 | { | |
5751 | em.addMember(sc, isAnon ? sds : ed); | |
5752 | } | |
5753 | } | |
5754 | }); | |
5755 | } | |
5756 | ||
5757 | void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* fargs) | |
5758 | { | |
5759 | //printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc); | |
5760 | version (none) | |
5761 | { | |
5762 | for (Dsymbol s = tempinst; s; s = s.parent) | |
5763 | { | |
5764 | printf("\t%s\n", s.toChars()); | |
5765 | } | |
5766 | printf("Scope\n"); | |
5767 | for (Scope* scx = sc; scx; scx = scx.enclosing) | |
5768 | { | |
5769 | printf("\t%s parent %s\n", scx._module ? scx._module.toChars() : "null", scx.parent ? scx.parent.toChars() : "null"); | |
5770 | } | |
5771 | } | |
5772 | ||
5773 | static if (LOG) | |
5774 | { | |
5775 | printf("\n+TemplateInstance.dsymbolSemantic('%s', this=%p)\n", tempinst.toChars(), tempinst); | |
5776 | } | |
5777 | if (tempinst.inst) // if semantic() was already run | |
5778 | { | |
5779 | static if (LOG) | |
5780 | { | |
5781 | printf("-TemplateInstance.dsymbolSemantic('%s', this=%p) already run\n", | |
5782 | tempinst.inst.toChars(), tempinst.inst); | |
5783 | } | |
5784 | return; | |
5785 | } | |
235d5a96 | 5786 | if (tempinst.semanticRun != PASS.initial) |
5fee5ec3 IB |
5787 | { |
5788 | static if (LOG) | |
5789 | { | |
5790 | printf("Recursive template expansion\n"); | |
5791 | } | |
5792 | auto ungag = Ungag(global.gag); | |
5793 | if (!tempinst.gagged) | |
5794 | global.gag = 0; | |
5795 | tempinst.error(tempinst.loc, "recursive template expansion"); | |
5796 | if (tempinst.gagged) | |
235d5a96 | 5797 | tempinst.semanticRun = PASS.initial; |
5fee5ec3 IB |
5798 | else |
5799 | tempinst.inst = tempinst; | |
5800 | tempinst.errors = true; | |
5801 | return; | |
5802 | } | |
5803 | ||
5804 | // Get the enclosing template instance from the scope tinst | |
5805 | tempinst.tinst = sc.tinst; | |
5806 | ||
5807 | // Get the instantiating module from the scope minst | |
5808 | tempinst.minst = sc.minst; | |
5809 | // https://issues.dlang.org/show_bug.cgi?id=10920 | |
5810 | // If the enclosing function is non-root symbol, | |
5811 | // this instance should be speculative. | |
5812 | if (!tempinst.tinst && sc.func && sc.func.inNonRoot()) | |
5813 | { | |
5814 | tempinst.minst = null; | |
5815 | } | |
5816 | ||
5817 | tempinst.gagged = (global.gag > 0); | |
5818 | ||
5819 | tempinst.semanticRun = PASS.semantic; | |
5820 | ||
5821 | static if (LOG) | |
5822 | { | |
5823 | printf("\tdo semantic\n"); | |
5824 | } | |
5825 | /* Find template declaration first, | |
5826 | * then run semantic on each argument (place results in tiargs[]), | |
5827 | * last find most specialized template from overload list/set. | |
5828 | */ | |
5829 | if (!tempinst.findTempDecl(sc, null) || !tempinst.semanticTiargs(sc) || !tempinst.findBestMatch(sc, fargs)) | |
5830 | { | |
5831 | Lerror: | |
5832 | if (tempinst.gagged) | |
5833 | { | |
5834 | // https://issues.dlang.org/show_bug.cgi?id=13220 | |
5835 | // Roll back status for later semantic re-running | |
235d5a96 | 5836 | tempinst.semanticRun = PASS.initial; |
5fee5ec3 IB |
5837 | } |
5838 | else | |
5839 | tempinst.inst = tempinst; | |
5840 | tempinst.errors = true; | |
5841 | return; | |
5842 | } | |
5843 | TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); | |
5844 | assert(tempdecl); | |
5845 | ||
5846 | TemplateStats.incInstance(tempdecl, tempinst); | |
5847 | ||
5848 | tempdecl.checkDeprecated(tempinst.loc, sc); | |
5849 | ||
5850 | // If tempdecl is a mixin, disallow it | |
5851 | if (tempdecl.ismixin) | |
5852 | { | |
5853 | tempinst.error("mixin templates are not regular templates"); | |
5854 | goto Lerror; | |
5855 | } | |
5856 | ||
5857 | tempinst.hasNestedArgs(tempinst.tiargs, tempdecl.isstatic); | |
5858 | if (tempinst.errors) | |
5859 | goto Lerror; | |
5860 | ||
5861 | // Copy the tempdecl namespace (not the scope one) | |
5862 | tempinst.cppnamespace = tempdecl.cppnamespace; | |
5863 | if (tempinst.cppnamespace) | |
5864 | tempinst.cppnamespace.dsymbolSemantic(sc); | |
5865 | ||
5866 | /* Greatly simplified semantic processing for AliasSeq templates | |
5867 | */ | |
5868 | if (tempdecl.isTrivialAliasSeq) | |
5869 | { | |
5870 | tempinst.inst = tempinst; | |
5871 | return aliasSeqInstanceSemantic(tempinst, sc, tempdecl); | |
5872 | } | |
5873 | ||
5874 | /* Greatly simplified semantic processing for Alias templates | |
5875 | */ | |
5876 | else if (tempdecl.isTrivialAlias) | |
5877 | { | |
5878 | tempinst.inst = tempinst; | |
5879 | return aliasInstanceSemantic(tempinst, sc, tempdecl); | |
5880 | } | |
5881 | ||
5882 | /* See if there is an existing TemplateInstantiation that already | |
5883 | * implements the typeargs. If so, just refer to that one instead. | |
5884 | */ | |
5885 | tempinst.inst = tempdecl.findExistingInstance(tempinst, fargs); | |
5886 | TemplateInstance errinst = null; | |
5887 | if (!tempinst.inst) | |
5888 | { | |
5889 | // So, we need to implement 'this' instance. | |
5890 | } | |
5891 | else if (tempinst.inst.gagged && !tempinst.gagged && tempinst.inst.errors) | |
5892 | { | |
5893 | // If the first instantiation had failed, re-run semantic, | |
5894 | // so that error messages are shown. | |
5895 | errinst = tempinst.inst; | |
5896 | } | |
5897 | else | |
5898 | { | |
5899 | // It's a match | |
5900 | tempinst.parent = tempinst.inst.parent; | |
5901 | tempinst.errors = tempinst.inst.errors; | |
5902 | ||
5903 | // If both this and the previous instantiation were gagged, | |
5904 | // use the number of errors that happened last time. | |
5905 | global.errors += tempinst.errors; | |
5906 | global.gaggedErrors += tempinst.errors; | |
5907 | ||
5908 | // If the first instantiation was gagged, but this is not: | |
5909 | if (tempinst.inst.gagged) | |
5910 | { | |
5911 | // It had succeeded, mark it is a non-gagged instantiation, | |
5912 | // and reuse it. | |
5913 | tempinst.inst.gagged = tempinst.gagged; | |
5914 | } | |
5915 | ||
5916 | tempinst.tnext = tempinst.inst.tnext; | |
5917 | tempinst.inst.tnext = tempinst; | |
5918 | ||
5919 | /* A module can have explicit template instance and its alias | |
5920 | * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`). | |
5921 | * If the first instantiation 'inst' had happened in non-root module, | |
5922 | * compiler can assume that its instantiated code would be included | |
5923 | * in the separately compiled obj/lib file (e.g. phobos.lib). | |
5924 | * | |
5925 | * However, if 'this' second instantiation happened in root module, | |
5926 | * compiler might need to invoke its codegen | |
5927 | * (https://issues.dlang.org/show_bug.cgi?id=2500 & https://issues.dlang.org/show_bug.cgi?id=2644). | |
5928 | * But whole import graph is not determined until all semantic pass finished, | |
5929 | * so 'inst' should conservatively finish the semantic3 pass for the codegen. | |
5930 | */ | |
5931 | if (tempinst.minst && tempinst.minst.isRoot() && !(tempinst.inst.minst && tempinst.inst.minst.isRoot())) | |
5932 | { | |
5933 | /* Swap the position of 'inst' and 'this' in the instantiation graph. | |
5934 | * Then, the primary instance `inst` will be changed to a root instance, | |
5935 | * along with all members of `inst` having their scopes updated. | |
5936 | * | |
5937 | * Before: | |
5938 | * non-root -> A!() -> B!()[inst] -> C!() { members[non-root] } | |
5939 | * | | |
5940 | * root -> D!() -> B!()[this] | |
5941 | * | |
5942 | * After: | |
5943 | * non-root -> A!() -> B!()[this] | |
5944 | * | | |
5945 | * root -> D!() -> B!()[inst] -> C!() { members[root] } | |
5946 | */ | |
5947 | Module mi = tempinst.minst; | |
5948 | TemplateInstance ti = tempinst.tinst; | |
5949 | tempinst.minst = tempinst.inst.minst; | |
5950 | tempinst.tinst = tempinst.inst.tinst; | |
5951 | tempinst.inst.minst = mi; | |
5952 | tempinst.inst.tinst = ti; | |
5953 | ||
5954 | /* https://issues.dlang.org/show_bug.cgi?id=21299 | |
5955 | `minst` has been updated on the primary instance `inst` so it is | |
5956 | now coming from a root module, however all Dsymbol `inst.members` | |
5957 | of the instance still have their `_scope.minst` pointing at the | |
5958 | original non-root module. We must now propagate `minst` to all | |
5959 | members so that forward referenced dependencies that get | |
5960 | instantiated will also be appended to the root module, otherwise | |
5961 | there will be undefined references at link-time. */ | |
5962 | extern (C++) final class InstMemberWalker : Visitor | |
5963 | { | |
5964 | alias visit = Visitor.visit; | |
5965 | TemplateInstance inst; | |
5966 | ||
5967 | extern (D) this(TemplateInstance inst) | |
5968 | { | |
5969 | this.inst = inst; | |
5970 | } | |
5971 | ||
5972 | override void visit(Dsymbol d) | |
5973 | { | |
5974 | if (d._scope) | |
5975 | d._scope.minst = inst.minst; | |
5976 | } | |
5977 | ||
5978 | override void visit(ScopeDsymbol sds) | |
5979 | { | |
5980 | sds.members.foreachDsymbol( s => s.accept(this) ); | |
5981 | visit(cast(Dsymbol)sds); | |
5982 | } | |
5983 | ||
5984 | override void visit(AttribDeclaration ad) | |
5985 | { | |
5986 | ad.include(null).foreachDsymbol( s => s.accept(this) ); | |
5987 | visit(cast(Dsymbol)ad); | |
5988 | } | |
5989 | ||
5990 | override void visit(ConditionalDeclaration cd) | |
5991 | { | |
5992 | if (cd.condition.inc) | |
5993 | visit(cast(AttribDeclaration)cd); | |
5994 | else | |
5995 | visit(cast(Dsymbol)cd); | |
5996 | } | |
5997 | } | |
5998 | scope v = new InstMemberWalker(tempinst.inst); | |
5999 | tempinst.inst.accept(v); | |
6000 | ||
6384eff5 IB |
6001 | if (!global.params.allInst && |
6002 | tempinst.minst) // if inst was not speculative... | |
5fee5ec3 | 6003 | { |
6384eff5 IB |
6004 | assert(!tempinst.minst.isRoot()); // ... it was previously appended to a non-root module |
6005 | // Append again to the root module members[], so that the instance will | |
6006 | // get codegen chances (depending on `tempinst.inst.needsCodegen()`). | |
5fee5ec3 IB |
6007 | tempinst.inst.appendToModuleMember(); |
6008 | } | |
6384eff5 IB |
6009 | |
6010 | assert(tempinst.inst.memberOf && tempinst.inst.memberOf.isRoot(), "no codegen chances"); | |
5fee5ec3 IB |
6011 | } |
6012 | ||
6013 | // modules imported by an existing instance should be added to the module | |
6014 | // that instantiates the instance. | |
6015 | if (tempinst.minst) | |
6016 | foreach(imp; tempinst.inst.importedModules) | |
6017 | if (!tempinst.minst.aimports.contains(imp)) | |
6018 | tempinst.minst.aimports.push(imp); | |
6019 | ||
6020 | static if (LOG) | |
6021 | { | |
6022 | printf("\tit's a match with instance %p, %d\n", tempinst.inst, tempinst.inst.semanticRun); | |
6023 | } | |
6024 | return; | |
6025 | } | |
6026 | static if (LOG) | |
6027 | { | |
6028 | printf("\timplement template instance %s '%s'\n", tempdecl.parent.toChars(), tempinst.toChars()); | |
6029 | printf("\ttempdecl %s\n", tempdecl.toChars()); | |
6030 | } | |
6031 | uint errorsave = global.errors; | |
6032 | ||
6033 | tempinst.inst = tempinst; | |
6034 | tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent; | |
6035 | //printf("parent = '%s'\n", parent.kind()); | |
6036 | ||
6037 | TemplateStats.incUnique(tempdecl, tempinst); | |
6038 | ||
6039 | TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst); | |
6040 | ||
6041 | //getIdent(); | |
6042 | ||
6043 | // Store the place we added it to in target_symbol_list(_idx) so we can | |
6044 | // remove it later if we encounter an error. | |
6045 | Dsymbols* target_symbol_list = tempinst.appendToModuleMember(); | |
6046 | size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list.dim - 1 : 0; | |
6047 | ||
6048 | // Copy the syntax trees from the TemplateDeclaration | |
6049 | tempinst.members = Dsymbol.arraySyntaxCopy(tempdecl.members); | |
6050 | ||
6051 | // resolve TemplateThisParameter | |
6052 | for (size_t i = 0; i < tempdecl.parameters.dim; i++) | |
6053 | { | |
6054 | if ((*tempdecl.parameters)[i].isTemplateThisParameter() is null) | |
6055 | continue; | |
6056 | Type t = isType((*tempinst.tiargs)[i]); | |
6057 | assert(t); | |
6058 | if (StorageClass stc = ModToStc(t.mod)) | |
6059 | { | |
6060 | //printf("t = %s, stc = x%llx\n", t.toChars(), stc); | |
6061 | auto s = new Dsymbols(); | |
6062 | s.push(new StorageClassDeclaration(stc, tempinst.members)); | |
6063 | tempinst.members = s; | |
6064 | } | |
6065 | break; | |
6066 | } | |
6067 | ||
6068 | // Create our own scope for the template parameters | |
6069 | Scope* _scope = tempdecl._scope; | |
235d5a96 | 6070 | if (tempdecl.semanticRun == PASS.initial) |
5fee5ec3 IB |
6071 | { |
6072 | tempinst.error("template instantiation `%s` forward references template declaration `%s`", tempinst.toChars(), tempdecl.toChars()); | |
6073 | return; | |
6074 | } | |
6075 | ||
6076 | static if (LOG) | |
6077 | { | |
6078 | printf("\tcreate scope for template parameters '%s'\n", tempinst.toChars()); | |
6079 | } | |
6080 | tempinst.argsym = new ScopeDsymbol(); | |
6081 | tempinst.argsym.parent = _scope.parent; | |
6082 | _scope = _scope.push(tempinst.argsym); | |
6083 | _scope.tinst = tempinst; | |
6084 | _scope.minst = tempinst.minst; | |
6085 | //scope.stc = 0; | |
6086 | ||
6087 | // Declare each template parameter as an alias for the argument type | |
6088 | Scope* paramscope = _scope.push(); | |
6089 | paramscope.stc = 0; | |
6090 | paramscope.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=14169 | |
6091 | // template parameters should be public | |
6092 | tempinst.declareParameters(paramscope); | |
6093 | paramscope.pop(); | |
6094 | ||
6095 | // Add members of template instance to template instance symbol table | |
6096 | //parent = scope.scopesym; | |
6097 | tempinst.symtab = new DsymbolTable(); | |
6098 | ||
6099 | tempinst.members.foreachDsymbol( (s) | |
6100 | { | |
6101 | static if (LOG) | |
6102 | { | |
6103 | printf("\t adding member '%s' %p kind %s to '%s'\n", s.toChars(), s, s.kind(), tempinst.toChars()); | |
6104 | } | |
6105 | s.addMember(_scope, tempinst); | |
6106 | }); | |
6107 | ||
6108 | static if (LOG) | |
6109 | { | |
6110 | printf("adding members done\n"); | |
6111 | } | |
6112 | ||
6113 | /* See if there is only one member of template instance, and that | |
6114 | * member has the same name as the template instance. | |
6115 | * If so, this template instance becomes an alias for that member. | |
6116 | */ | |
6117 | //printf("members.dim = %d\n", tempinst.members.dim); | |
6118 | if (tempinst.members.dim) | |
6119 | { | |
6120 | Dsymbol s; | |
6121 | if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) | |
6122 | { | |
6123 | //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); | |
6124 | //printf("setting aliasdecl\n"); | |
6125 | tempinst.aliasdecl = s; | |
6126 | } | |
6127 | } | |
6128 | ||
6129 | /* If function template declaration | |
6130 | */ | |
6131 | if (fargs && tempinst.aliasdecl) | |
6132 | { | |
6133 | if (auto fd = tempinst.aliasdecl.isFuncDeclaration()) | |
6134 | { | |
6135 | /* Transmit fargs to type so that TypeFunction.dsymbolSemantic() can | |
6136 | * resolve any "auto ref" storage classes. | |
6137 | */ | |
6138 | if (fd.type) | |
6139 | if (auto tf = fd.type.isTypeFunction()) | |
6140 | tf.fargs = fargs; | |
6141 | } | |
6142 | } | |
6143 | ||
6144 | // Do semantic() analysis on template instance members | |
6145 | static if (LOG) | |
6146 | { | |
6147 | printf("\tdo semantic() on template instance members '%s'\n", tempinst.toChars()); | |
6148 | } | |
6149 | Scope* sc2; | |
6150 | sc2 = _scope.push(tempinst); | |
6151 | //printf("enclosing = %d, sc.parent = %s\n", tempinst.enclosing, sc.parent.toChars()); | |
6152 | sc2.parent = tempinst; | |
6153 | sc2.tinst = tempinst; | |
6154 | sc2.minst = tempinst.minst; | |
6155 | sc2.stc &= ~STC.deprecated_; | |
6156 | tempinst.tryExpandMembers(sc2); | |
6157 | ||
6158 | tempinst.semanticRun = PASS.semanticdone; | |
6159 | ||
6160 | /* ConditionalDeclaration may introduce eponymous declaration, | |
6161 | * so we should find it once again after semantic. | |
6162 | */ | |
6163 | if (tempinst.members.dim) | |
6164 | { | |
6165 | Dsymbol s; | |
6166 | if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) | |
6167 | { | |
6168 | if (!tempinst.aliasdecl || tempinst.aliasdecl != s) | |
6169 | { | |
6170 | //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); | |
6171 | //printf("setting aliasdecl 2\n"); | |
6172 | tempinst.aliasdecl = s; | |
6173 | } | |
6174 | } | |
6175 | } | |
6176 | ||
6177 | if (global.errors != errorsave) | |
6178 | goto Laftersemantic; | |
6179 | ||
6180 | /* If any of the instantiation members didn't get semantic() run | |
6181 | * on them due to forward references, we cannot run semantic2() | |
6182 | * or semantic3() yet. | |
6183 | */ | |
6184 | { | |
6185 | bool found_deferred_ad = false; | |
6186 | for (size_t i = 0; i < Module.deferred.dim; i++) | |
6187 | { | |
6188 | Dsymbol sd = Module.deferred[i]; | |
6189 | AggregateDeclaration ad = sd.isAggregateDeclaration(); | |
6190 | if (ad && ad.parent && ad.parent.isTemplateInstance()) | |
6191 | { | |
6192 | //printf("deferred template aggregate: %s %s\n", | |
6193 | // sd.parent.toChars(), sd.toChars()); | |
6194 | found_deferred_ad = true; | |
6195 | if (ad.parent == tempinst) | |
6196 | { | |
6197 | ad.deferred = tempinst; | |
6198 | break; | |
6199 | } | |
6200 | } | |
6201 | } | |
6202 | if (found_deferred_ad || Module.deferred.dim) | |
6203 | goto Laftersemantic; | |
6204 | } | |
6205 | ||
6206 | /* The problem is when to parse the initializer for a variable. | |
6207 | * Perhaps VarDeclaration.dsymbolSemantic() should do it like it does | |
6208 | * for initializers inside a function. | |
6209 | */ | |
6210 | //if (sc.parent.isFuncDeclaration()) | |
6211 | { | |
6212 | /* https://issues.dlang.org/show_bug.cgi?id=782 | |
6213 | * this has problems if the classes this depends on | |
6214 | * are forward referenced. Find a way to defer semantic() | |
6215 | * on this template. | |
6216 | */ | |
6217 | tempinst.semantic2(sc2); | |
6218 | } | |
6219 | if (global.errors != errorsave) | |
6220 | goto Laftersemantic; | |
6221 | ||
6222 | if ((sc.func || (sc.flags & SCOPE.fullinst)) && !tempinst.tinst) | |
6223 | { | |
6224 | /* If a template is instantiated inside function, the whole instantiation | |
6225 | * should be done at that position. But, immediate running semantic3 of | |
6226 | * dependent templates may cause unresolved forward reference. | |
6227 | * https://issues.dlang.org/show_bug.cgi?id=9050 | |
6228 | * To avoid the issue, don't run semantic3 until semantic and semantic2 done. | |
6229 | */ | |
6230 | TemplateInstances deferred; | |
6231 | tempinst.deferred = &deferred; | |
6232 | ||
6233 | //printf("Run semantic3 on %s\n", toChars()); | |
6234 | tempinst.trySemantic3(sc2); | |
6235 | ||
6236 | for (size_t i = 0; i < deferred.dim; i++) | |
6237 | { | |
6238 | //printf("+ run deferred semantic3 on %s\n", deferred[i].toChars()); | |
6239 | deferred[i].semantic3(null); | |
6240 | } | |
6241 | ||
6242 | tempinst.deferred = null; | |
6243 | } | |
6244 | else if (tempinst.tinst) | |
6245 | { | |
6246 | bool doSemantic3 = false; | |
6247 | FuncDeclaration fd; | |
6248 | if (tempinst.aliasdecl) | |
6249 | fd = tempinst.aliasdecl.toAlias2().isFuncDeclaration(); | |
6250 | ||
6251 | if (fd) | |
6252 | { | |
6253 | /* Template function instantiation should run semantic3 immediately | |
6254 | * for attribute inference. | |
6255 | */ | |
6256 | scope fld = fd.isFuncLiteralDeclaration(); | |
6257 | if (fld && fld.tok == TOK.reserved) | |
6258 | doSemantic3 = true; | |
6259 | else if (sc.func) | |
6260 | doSemantic3 = true; | |
6261 | } | |
6262 | else if (sc.func) | |
6263 | { | |
6264 | /* A lambda function in template arguments might capture the | |
6265 | * instantiated scope context. For the correct context inference, | |
6266 | * all instantiated functions should run the semantic3 immediately. | |
6267 | * See also compilable/test14973.d | |
6268 | */ | |
6269 | foreach (oarg; tempinst.tdtypes) | |
6270 | { | |
6271 | auto s = getDsymbol(oarg); | |
6272 | if (!s) | |
6273 | continue; | |
6274 | ||
6275 | if (auto td = s.isTemplateDeclaration()) | |
6276 | { | |
6277 | if (!td.literal) | |
6278 | continue; | |
6279 | assert(td.members && td.members.dim == 1); | |
6280 | s = (*td.members)[0]; | |
6281 | } | |
6282 | if (auto fld = s.isFuncLiteralDeclaration()) | |
6283 | { | |
6284 | if (fld.tok == TOK.reserved) | |
6285 | { | |
6286 | doSemantic3 = true; | |
6287 | break; | |
6288 | } | |
6289 | } | |
6290 | } | |
6291 | //printf("[%s] %s doSemantic3 = %d\n", tempinst.tinst.loc.toChars(), tempinst.tinst.toChars(), doSemantic3); | |
6292 | } | |
6293 | if (doSemantic3) | |
6294 | tempinst.trySemantic3(sc2); | |
6295 | ||
6296 | TemplateInstance ti = tempinst.tinst; | |
6297 | int nest = 0; | |
6298 | while (ti && !ti.deferred && ti.tinst) | |
6299 | { | |
6300 | ti = ti.tinst; | |
6301 | if (++nest > global.recursionLimit) | |
6302 | { | |
6303 | global.gag = 0; // ensure error message gets printed | |
6304 | tempinst.error("recursive expansion"); | |
6305 | fatal(); | |
6306 | } | |
6307 | } | |
6308 | if (ti && ti.deferred) | |
6309 | { | |
6310 | //printf("deferred semantic3 of %p %s, ti = %s, ti.deferred = %p\n", this, toChars(), ti.toChars()); | |
6311 | for (size_t i = 0;; i++) | |
6312 | { | |
6313 | if (i == ti.deferred.dim) | |
6314 | { | |
6315 | ti.deferred.push(tempinst); | |
6316 | break; | |
6317 | } | |
6318 | if ((*ti.deferred)[i] == tempinst) | |
6319 | break; | |
6320 | } | |
6321 | } | |
6322 | } | |
6323 | ||
6324 | if (tempinst.aliasdecl) | |
6325 | { | |
6326 | /* https://issues.dlang.org/show_bug.cgi?id=13816 | |
6327 | * AliasDeclaration tries to resolve forward reference | |
6328 | * twice (See inuse check in AliasDeclaration.toAlias()). It's | |
6329 | * necessary to resolve mutual references of instantiated symbols, but | |
6330 | * it will left a true recursive alias in tuple declaration - an | |
6331 | * AliasDeclaration A refers TupleDeclaration B, and B contains A | |
6332 | * in its elements. To correctly make it an error, we strictly need to | |
6333 | * resolve the alias of eponymous member. | |
6334 | */ | |
6335 | tempinst.aliasdecl = tempinst.aliasdecl.toAlias2(); | |
b7a586be IB |
6336 | |
6337 | // stop AliasAssign tuple building | |
6338 | if (auto td = tempinst.aliasdecl.isTupleDeclaration()) | |
6339 | td.building = false; | |
5fee5ec3 IB |
6340 | } |
6341 | ||
6342 | Laftersemantic: | |
6343 | sc2.pop(); | |
6344 | _scope.pop(); | |
6345 | ||
6346 | // Give additional context info if error occurred during instantiation | |
6347 | if (global.errors != errorsave) | |
6348 | { | |
6349 | if (!tempinst.errors) | |
6350 | { | |
6351 | if (!tempdecl.literal) | |
6352 | tempinst.error(tempinst.loc, "error instantiating"); | |
6353 | if (tempinst.tinst) | |
6354 | tempinst.tinst.printInstantiationTrace(); | |
6355 | } | |
6356 | tempinst.errors = true; | |
6357 | if (tempinst.gagged) | |
6358 | { | |
6359 | // Errors are gagged, so remove the template instance from the | |
6360 | // instance/symbol lists we added it to and reset our state to | |
6361 | // finish clean and so we can try to instantiate it again later | |
6362 | // (see https://issues.dlang.org/show_bug.cgi?id=4302 and https://issues.dlang.org/show_bug.cgi?id=6602). | |
6363 | tempdecl.removeInstance(tempdecl_instance_idx); | |
6364 | if (target_symbol_list) | |
6365 | { | |
6366 | // Because we added 'this' in the last position above, we | |
6367 | // should be able to remove it without messing other indices up. | |
6368 | assert((*target_symbol_list)[target_symbol_list_idx] == tempinst); | |
6369 | target_symbol_list.remove(target_symbol_list_idx); | |
6370 | tempinst.memberOf = null; // no longer a member | |
6371 | } | |
235d5a96 | 6372 | tempinst.semanticRun = PASS.initial; |
5fee5ec3 IB |
6373 | tempinst.inst = null; |
6374 | tempinst.symtab = null; | |
6375 | } | |
6376 | } | |
6377 | else if (errinst) | |
6378 | { | |
6379 | /* https://issues.dlang.org/show_bug.cgi?id=14541 | |
6380 | * If the previous gagged instance had failed by | |
6381 | * circular references, currrent "error reproduction instantiation" | |
6382 | * might succeed, because of the difference of instantiated context. | |
6383 | * On such case, the cached error instance needs to be overridden by the | |
6384 | * succeeded instance. | |
6385 | */ | |
6386 | //printf("replaceInstance()\n"); | |
6387 | assert(errinst.errors); | |
6388 | auto ti1 = TemplateInstanceBox(errinst); | |
6389 | tempdecl.instances.remove(ti1); | |
6390 | ||
6391 | auto ti2 = TemplateInstanceBox(tempinst); | |
6392 | tempdecl.instances[ti2] = tempinst; | |
6393 | } | |
6394 | ||
6395 | static if (LOG) | |
6396 | { | |
6397 | printf("-TemplateInstance.dsymbolSemantic('%s', this=%p)\n", tempinst.toChars(), tempinst); | |
6398 | } | |
6399 | } | |
6400 | ||
6401 | /****************************************************** | |
6402 | * Do template instance semantic for isAliasSeq templates. | |
6403 | * This is a greatly simplified version of templateInstanceSemantic(). | |
6404 | */ | |
6405 | private | |
6406 | void aliasSeqInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclaration tempdecl) | |
6407 | { | |
6408 | //printf("[%s] aliasSeqInstance.dsymbolSemantic('%s')\n", tempinst.loc.toChars(), tempinst.toChars()); | |
6409 | Scope* paramscope = sc.push(); | |
6410 | paramscope.stc = 0; | |
6411 | paramscope.visibility = Visibility(Visibility.Kind.public_); | |
6412 | ||
6413 | TemplateTupleParameter ttp = (*tempdecl.parameters)[0].isTemplateTupleParameter(); | |
6414 | Tuple va = tempinst.tdtypes[0].isTuple(); | |
6415 | Declaration d = new TupleDeclaration(tempinst.loc, ttp.ident, &va.objects); | |
6416 | d.storage_class |= STC.templateparameter; | |
6417 | d.dsymbolSemantic(sc); | |
6418 | ||
6419 | paramscope.pop(); | |
6420 | ||
6421 | tempinst.aliasdecl = d; | |
6422 | ||
6423 | tempinst.semanticRun = PASS.semanticdone; | |
6424 | } | |
6425 | ||
6426 | /****************************************************** | |
6427 | * Do template instance semantic for isAlias templates. | |
6428 | * This is a greatly simplified version of templateInstanceSemantic(). | |
6429 | */ | |
6430 | private | |
6431 | void aliasInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclaration tempdecl) | |
6432 | { | |
6433 | //printf("[%s] aliasInstance.dsymbolSemantic('%s')\n", tempinst.loc.toChars(), tempinst.toChars()); | |
6434 | Scope* paramscope = sc.push(); | |
6435 | paramscope.stc = 0; | |
6436 | paramscope.visibility = Visibility(Visibility.Kind.public_); | |
6437 | ||
6438 | TemplateTypeParameter ttp = (*tempdecl.parameters)[0].isTemplateTypeParameter(); | |
6439 | Type ta = tempinst.tdtypes[0].isType(); | |
6440 | auto ad = tempdecl.onemember.isAliasDeclaration(); | |
6441 | ||
6442 | // Note: qualifiers can be in both 'ad.type.mod' and 'ad.storage_class' | |
6443 | Declaration d = new AliasDeclaration(tempinst.loc, ttp.ident, ta.addMod(ad.type.mod)); | |
6444 | d.storage_class |= STC.templateparameter | ad.storage_class; | |
6445 | d.dsymbolSemantic(sc); | |
6446 | ||
6447 | paramscope.pop(); | |
6448 | ||
6449 | tempinst.aliasdecl = d; | |
6450 | ||
6451 | tempinst.semanticRun = PASS.semanticdone; | |
6452 | } | |
6453 | ||
6454 | // function used to perform semantic on AliasDeclaration | |
6455 | void aliasSemantic(AliasDeclaration ds, Scope* sc) | |
6456 | { | |
6457 | //printf("AliasDeclaration::semantic() %s\n", ds.toChars()); | |
6458 | ||
6459 | // as DsymbolSemanticVisitor::visit(AliasDeclaration), in case we're called first. | |
6460 | // see https://issues.dlang.org/show_bug.cgi?id=21001 | |
6461 | ds.storage_class |= sc.stc & STC.deprecated_; | |
6462 | ds.visibility = sc.visibility; | |
6463 | ds.userAttribDecl = sc.userAttribDecl; | |
6464 | ||
5fee5ec3 IB |
6465 | void normalRet() |
6466 | { | |
5fee5ec3 IB |
6467 | ds.inuse = 0; |
6468 | ds.semanticRun = PASS.semanticdone; | |
6469 | ||
6470 | if (auto sx = ds.overnext) | |
6471 | { | |
6472 | ds.overnext = null; | |
6473 | if (!ds.overloadInsert(sx)) | |
6474 | ScopeDsymbol.multiplyDefined(Loc.initial, sx, ds); | |
6475 | } | |
6476 | } | |
6477 | ||
6478 | void errorRet() | |
6479 | { | |
6480 | ds.aliassym = null; | |
6481 | ds.type = Type.terror; | |
6482 | ds.inuse = 0; | |
6483 | normalRet(); | |
6484 | } | |
6485 | ||
6486 | // preserve the original type | |
6487 | if (!ds.originalType && ds.type) | |
6488 | ds.originalType = ds.type.syntaxCopy(); | |
6489 | ||
6490 | if (ds.aliassym) | |
6491 | { | |
6492 | auto fd = ds.aliassym.isFuncLiteralDeclaration(); | |
6493 | auto td = ds.aliassym.isTemplateDeclaration(); | |
6494 | if (fd || td && td.literal) | |
6495 | { | |
6496 | if (fd && fd.semanticRun >= PASS.semanticdone) | |
6497 | return normalRet(); | |
6498 | ||
6499 | Expression e = new FuncExp(ds.loc, ds.aliassym); | |
6500 | e = e.expressionSemantic(sc); | |
6501 | if (auto fe = e.isFuncExp()) | |
6502 | { | |
6503 | ds.aliassym = fe.td ? cast(Dsymbol)fe.td : fe.fd; | |
6504 | return normalRet(); | |
6505 | } | |
6506 | else | |
6507 | return errorRet(); | |
6508 | } | |
6509 | ||
6510 | if (ds.aliassym.isTemplateInstance()) | |
6511 | ds.aliassym.dsymbolSemantic(sc); | |
6512 | return normalRet(); | |
6513 | } | |
6514 | ds.inuse = 1; | |
6515 | ||
6516 | // Given: | |
6517 | // alias foo.bar.abc def; | |
6518 | // it is not knowable from the syntax whether `def` is an alias | |
6519 | // for type `foo.bar.abc` or an alias for symbol `foo.bar.abc`. It is up to the semantic() | |
6520 | // pass to distinguish. | |
6521 | // If it is a type, then `.type` is set and getType() will return that | |
6522 | // type. If it is a symbol, then `.aliassym` is set and type is `null` - | |
6523 | // toAlias() will return `.aliassym` | |
6524 | ||
6525 | const errors = global.errors; | |
6526 | Type oldtype = ds.type; | |
6527 | ||
6528 | // Ungag errors when not instantiated DeclDefs scope alias | |
6529 | auto ungag = Ungag(global.gag); | |
235d5a96 IB |
6530 | //printf("%s parent = %s, gag = %d, instantiated = %d\n", ds.toChars(), ds.parent.toChars(), global.gag, ds.isInstantiated() !is null); |
6531 | if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration() && (sc.minst || sc.tinst)) | |
5fee5ec3 | 6532 | { |
235d5a96 | 6533 | //printf("%s type = %s\n", ds.toPrettyChars(), ds.type.toChars()); |
5fee5ec3 IB |
6534 | global.gag = 0; |
6535 | } | |
6536 | ||
6537 | // https://issues.dlang.org/show_bug.cgi?id=18480 | |
6538 | // Detect `alias sym = sym;` to prevent creating loops in overload overnext lists. | |
6539 | if (auto tident = ds.type.isTypeIdentifier()) | |
6540 | { | |
6541 | // Selective imports are allowed to alias to the same name `import mod : sym=sym`. | |
6542 | if (!ds._import) | |
6543 | { | |
6544 | if (tident.ident is ds.ident && !tident.idents.dim) | |
6545 | { | |
6546 | error(ds.loc, "`alias %s = %s;` cannot alias itself, use a qualified name to create an overload set", | |
6547 | ds.ident.toChars(), tident.ident.toChars()); | |
6548 | ds.type = Type.terror; | |
6549 | } | |
6550 | } | |
6551 | } | |
6552 | /* This section is needed because Type.resolve() will: | |
6553 | * const x = 3; | |
6554 | * alias y = x; | |
6555 | * try to convert identifier x to 3. | |
6556 | */ | |
6557 | auto s = ds.type.toDsymbol(sc); | |
6558 | if (errors != global.errors) | |
6559 | return errorRet(); | |
6560 | if (s == ds) | |
6561 | { | |
6562 | ds.error("cannot resolve"); | |
6563 | return errorRet(); | |
6564 | } | |
6565 | if (!s || !s.isEnumMember()) | |
6566 | { | |
6567 | Type t; | |
6568 | Expression e; | |
6569 | Scope* sc2 = sc; | |
6570 | if (ds.storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.disable)) | |
6571 | { | |
6572 | // For 'ref' to be attached to function types, and picked | |
6573 | // up by Type.resolve(), it has to go into sc. | |
6574 | sc2 = sc.push(); | |
6575 | sc2.stc |= ds.storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable); | |
6576 | } | |
6577 | ds.type = ds.type.addSTC(ds.storage_class); | |
6578 | ds.type.resolve(ds.loc, sc2, e, t, s); | |
6579 | if (sc2 != sc) | |
6580 | sc2.pop(); | |
6581 | ||
6582 | if (e) // Try to convert Expression to Dsymbol | |
6583 | { | |
6584 | // TupleExp is naturally converted to a TupleDeclaration | |
6585 | if (auto te = e.isTupleExp()) | |
6586 | s = new TupleDeclaration(te.loc, ds.ident, cast(Objects*)te.exps); | |
6587 | else | |
6588 | { | |
6589 | s = getDsymbol(e); | |
6590 | if (!s) | |
6591 | { | |
9c7d5e88 | 6592 | if (e.op != EXP.error) |
5fee5ec3 IB |
6593 | ds.error("cannot alias an expression `%s`", e.toChars()); |
6594 | return errorRet(); | |
6595 | } | |
6596 | } | |
6597 | } | |
6598 | ds.type = t; | |
6599 | } | |
6600 | if (s == ds) | |
6601 | { | |
6602 | assert(global.errors); | |
6603 | return errorRet(); | |
6604 | } | |
6605 | if (s) // it's a symbolic alias | |
6606 | { | |
235d5a96 | 6607 | //printf("alias %s resolved to %s %s\n", ds.toChars(), s.kind(), s.toChars()); |
5fee5ec3 IB |
6608 | ds.type = null; |
6609 | ds.aliassym = s; | |
6610 | } | |
6611 | else // it's a type alias | |
6612 | { | |
235d5a96 | 6613 | //printf("alias %s resolved to type %s\n", ds.toChars(), ds.type.toChars()); |
5fee5ec3 IB |
6614 | ds.type = ds.type.typeSemantic(ds.loc, sc); |
6615 | ds.aliassym = null; | |
6616 | } | |
6617 | ||
6618 | if (global.gag && errors != global.errors) | |
6619 | return errorRet(); | |
6620 | ||
6621 | normalRet(); | |
6622 | } | |
6623 | ||
6624 | /******************** | |
6625 | * Perform semantic on AliasAssignment. | |
6626 | * Has a lot of similarities to aliasSemantic(). Perhaps they should share code. | |
6627 | */ | |
6628 | private void aliasAssignSemantic(AliasAssign ds, Scope* sc) | |
6629 | { | |
6630 | //printf("AliasAssign::semantic() %p, %s\n", ds, ds.ident.toChars()); | |
6631 | ||
6632 | void errorRet() | |
6633 | { | |
6634 | ds.errors = true; | |
6635 | ds.type = Type.terror; | |
6636 | ds.semanticRun = PASS.semanticdone; | |
6637 | return; | |
6638 | } | |
6639 | ||
6640 | /* Find the AliasDeclaration corresponding to ds. | |
6641 | * Returns: AliasDeclaration if found, null if error | |
6642 | */ | |
6643 | AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc) | |
6644 | { | |
6645 | Dsymbol scopesym; | |
6646 | Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym); | |
6647 | if (!as) | |
6648 | { | |
6649 | ds.error("undefined identifier `%s`", ds.ident.toChars()); | |
6650 | return null; | |
6651 | } | |
6652 | if (as.errors) | |
6653 | return null; | |
6654 | ||
6655 | auto ad = as.isAliasDeclaration(); | |
6656 | if (!ad) | |
6657 | { | |
6658 | ds.error("identifier `%s` must be an alias declaration", as.toChars()); | |
6659 | return null; | |
6660 | } | |
6661 | ||
6662 | if (ad.overnext) | |
6663 | { | |
6664 | ds.error("cannot reassign overloaded alias"); | |
6665 | return null; | |
6666 | } | |
6667 | ||
6668 | // Check constraints on the parent | |
6669 | auto adParent = ad.toParent(); | |
6670 | if (adParent != ds.toParent()) | |
6671 | { | |
6672 | if (!adParent) | |
6673 | adParent = ds.toParent(); | |
6674 | error(ds.loc, "`%s` must have same parent `%s` as alias `%s`", ds.ident.toChars(), adParent.toChars(), ad.toChars()); | |
6675 | return null; | |
6676 | } | |
6677 | if (!adParent.isTemplateInstance()) | |
6678 | { | |
6679 | ds.error("must be a member of a template"); | |
6680 | return null; | |
6681 | } | |
6682 | ||
6683 | return ad; | |
6684 | } | |
6685 | ||
6686 | auto aliassym = findAliasDeclaration(ds, sc); | |
6687 | if (!aliassym) | |
6688 | return errorRet(); | |
6689 | ||
6690 | if (aliassym.adFlags & Declaration.wasRead) | |
6691 | { | |
6692 | if (!aliassym.errors) | |
6693 | error(ds.loc, "%s was read, so cannot reassign", aliassym.toChars()); | |
6694 | aliassym.errors = true; | |
6695 | return errorRet(); | |
6696 | } | |
6697 | ||
6698 | aliassym.adFlags |= Declaration.ignoreRead; // temporarilly allow reads of aliassym | |
6699 | ||
6700 | const storage_class = sc.stc & (STC.deprecated_ | STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable); | |
6701 | ||
6702 | if (ds.aliassym) | |
6703 | { | |
6704 | auto fd = ds.aliassym.isFuncLiteralDeclaration(); | |
6705 | auto td = ds.aliassym.isTemplateDeclaration(); | |
6706 | if (fd && fd.semanticRun >= PASS.semanticdone) | |
6707 | { | |
6708 | } | |
6709 | else if (fd || td && td.literal) | |
6710 | { | |
6711 | ||
6712 | Expression e = new FuncExp(ds.loc, ds.aliassym); | |
6713 | e = e.expressionSemantic(sc); | |
6714 | auto fe = e.isFuncExp(); | |
6715 | if (!fe) | |
6716 | return errorRet(); | |
6717 | ds.aliassym = fe.td ? cast(Dsymbol)fe.td : fe.fd; | |
6718 | } | |
6719 | else if (ds.aliassym.isTemplateInstance()) | |
6720 | ds.aliassym.dsymbolSemantic(sc); | |
6721 | ||
6722 | aliassym.type = null; | |
6723 | aliassym.aliassym = ds.aliassym; | |
6724 | return; | |
6725 | } | |
6726 | ||
6727 | /* Given: | |
6728 | * abc = def; | |
6729 | * it is not knownable from the syntax whether `def` is a type or a symbol. | |
6730 | * It appears here as `ds.type`. Do semantic analysis on `def` to disambiguate. | |
6731 | */ | |
6732 | ||
6733 | const errors = global.errors; | |
b7a586be IB |
6734 | Dsymbol s; |
6735 | ||
6736 | // Try AliasSeq optimization | |
6737 | if (auto ti = ds.type.isTypeInstance()) | |
6738 | { | |
6739 | if (!ti.tempinst.findTempDecl(sc, null)) | |
6740 | return errorRet(); | |
6741 | if (auto tempinst = isAliasSeq(sc, ti)) | |
6742 | { | |
6743 | s = aliasAssignInPlace(sc, tempinst, aliassym); | |
6744 | if (!s) | |
6745 | return errorRet(); | |
6746 | goto Lsymdone; | |
6747 | } | |
6748 | } | |
5fee5ec3 IB |
6749 | |
6750 | /* This section is needed because Type.resolve() will: | |
6751 | * const x = 3; | |
6752 | * alias y = x; | |
6753 | * try to convert identifier x to 3. | |
6754 | */ | |
b7a586be | 6755 | s = ds.type.toDsymbol(sc); |
5fee5ec3 IB |
6756 | if (errors != global.errors) |
6757 | return errorRet(); | |
6758 | if (s == aliassym) | |
6759 | { | |
6760 | ds.error("cannot resolve"); | |
6761 | return errorRet(); | |
6762 | } | |
6763 | ||
6764 | if (!s || !s.isEnumMember()) | |
6765 | { | |
6766 | Type t; | |
6767 | Expression e; | |
6768 | Scope* sc2 = sc; | |
6769 | if (storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable)) | |
6770 | { | |
6771 | // For 'ref' to be attached to function types, and picked | |
6772 | // up by Type.resolve(), it has to go into sc. | |
6773 | sc2 = sc.push(); | |
6774 | sc2.stc |= storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable); | |
6775 | } | |
6776 | ds.type = ds.type.addSTC(storage_class); | |
6777 | ds.type.resolve(ds.loc, sc2, e, t, s); | |
6778 | if (sc2 != sc) | |
6779 | sc2.pop(); | |
6780 | ||
6781 | if (e) // Try to convert Expression to Dsymbol | |
6782 | { | |
6783 | // TupleExp is naturally converted to a TupleDeclaration | |
6784 | if (auto te = e.isTupleExp()) | |
6785 | s = new TupleDeclaration(te.loc, ds.ident, cast(Objects*)te.exps); | |
6786 | else | |
6787 | { | |
6788 | s = getDsymbol(e); | |
6789 | if (!s) | |
6790 | { | |
9c7d5e88 | 6791 | if (e.op != EXP.error) |
5fee5ec3 IB |
6792 | ds.error("cannot alias an expression `%s`", e.toChars()); |
6793 | return errorRet(); | |
6794 | } | |
6795 | } | |
6796 | } | |
6797 | ds.type = t; | |
6798 | } | |
6799 | if (s == aliassym) | |
6800 | { | |
6801 | assert(global.errors); | |
6802 | return errorRet(); | |
6803 | } | |
6804 | ||
6805 | if (s) // it's a symbolic alias | |
6806 | { | |
b7a586be | 6807 | Lsymdone: |
5fee5ec3 IB |
6808 | //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars()); |
6809 | aliassym.type = null; | |
6810 | aliassym.aliassym = s; | |
6811 | aliassym.storage_class |= sc.stc & STC.deprecated_; | |
6812 | aliassym.visibility = sc.visibility; | |
6813 | aliassym.userAttribDecl = sc.userAttribDecl; | |
6814 | } | |
6815 | else // it's a type alias | |
6816 | { | |
6817 | //printf("alias %s resolved to type %s\n", toChars(), type.toChars()); | |
6818 | aliassym.type = ds.type.typeSemantic(ds.loc, sc); | |
6819 | aliassym.aliassym = null; | |
6820 | } | |
6821 | ||
6822 | ||
6823 | aliassym.adFlags &= ~Declaration.ignoreRead; | |
6824 | ||
6825 | if (aliassym.type && aliassym.type.ty == Terror || | |
6826 | global.gag && errors != global.errors) | |
6827 | { | |
6828 | aliassym.type = Type.terror; | |
6829 | aliassym.aliassym = null; | |
6830 | return errorRet(); | |
6831 | } | |
6832 | ||
6833 | ds.semanticRun = PASS.semanticdone; | |
6834 | } | |
6835 | ||
b7a586be IB |
6836 | /*************************************** |
6837 | * Expands template instance arguments inside 'alias assign' target declaration (aliassym), | |
6838 | * instead of inside 'tempinst.tiargs' every time. | |
6839 | * Params: | |
6840 | * tempinst = AliasSeq instance | |
6841 | * aliassym = the AliasDeclaration corresponding to AliasAssign | |
6842 | * Returns: | |
6843 | * null. | |
6844 | */ | |
6845 | private TupleDeclaration aliasAssignInPlace(Scope* sc, TemplateInstance tempinst, | |
6846 | AliasDeclaration aliassym) | |
6847 | { | |
6848 | // Mark instance with semantic done, not needed but just in case. | |
6849 | tempinst.inst = tempinst; | |
6850 | tempinst.semanticRun = PASS.semanticdone; | |
6851 | TupleDeclaration td; | |
6852 | if (aliassym.type) | |
6853 | { | |
6854 | // Convert TypeTuple to TupleDeclaration to avoid back and forth allocations | |
6855 | // in the assignment process | |
6856 | if (auto tt = aliassym.type.isTypeTuple()) | |
6857 | { | |
6858 | auto objs = new Objects(tt.arguments.length); | |
6859 | foreach (i, p; *tt.arguments) | |
6860 | (*objs)[i] = p.type; | |
6861 | td = new TupleDeclaration(tempinst.loc, aliassym.ident, objs); | |
6862 | td.storage_class |= STC.templateparameter; | |
6863 | td.building = true; | |
6864 | aliassym.type = null; | |
6865 | } | |
6866 | else if (aliassym.type.isTypeError()) | |
6867 | return null; | |
6868 | ||
6869 | } | |
6870 | else if (auto otd = aliassym.aliassym.isTupleDeclaration()) | |
6871 | { | |
6872 | if (otd.building) | |
6873 | td = otd; | |
6874 | else | |
6875 | { | |
6876 | td = new TupleDeclaration(tempinst.loc, aliassym.ident, otd.objects.copy()); | |
6877 | td.storage_class |= STC.templateparameter; | |
6878 | td.building = true; | |
6879 | } | |
6880 | } | |
6881 | // If starting from single element in aliassym (td == null) we need to build the tuple | |
6882 | // after semanticTiargs to keep same semantics (for example a FuncLiteraldeclaration | |
6883 | // template argument is converted to FuncExp) | |
6884 | if (td) | |
6885 | aliassym.aliassym = td; | |
6886 | aliassym.semanticRun = PASS.semanticdone; | |
6887 | if (!TemplateInstance.semanticTiargs(tempinst.loc, sc, tempinst.tiargs, 0, td)) | |
6888 | { | |
6889 | tempinst.errors = true; | |
6890 | return null; | |
6891 | } | |
6892 | // The alias will stop tuple 'building' mode when used (in AliasDeclaration.toAlias(), | |
6893 | // then TupleDeclaration.getType() will work again) | |
6894 | aliassym.semanticRun = PASS.initial; | |
6895 | if (!td) | |
6896 | { | |
6897 | td = new TupleDeclaration(tempinst.loc, aliassym.ident, tempinst.tiargs); | |
6898 | td.storage_class |= STC.templateparameter; | |
6899 | td.building = true; | |
6900 | return td; | |
6901 | } | |
6902 | ||
6903 | auto tiargs = tempinst.tiargs; | |
6904 | size_t oldlen = td.objects.length; | |
6905 | size_t origstart; | |
6906 | size_t insertidx; | |
6907 | size_t insertlen; | |
6908 | foreach (i, o; *tiargs) | |
6909 | { | |
6910 | if (o !is td) | |
6911 | { | |
6912 | ++insertlen; | |
6913 | continue; | |
6914 | } | |
6915 | // tuple contains itself (tuple = AliasSeq!(..., tuple, ...)) | |
6916 | if (insertlen) // insert any left element before | |
6917 | { | |
6918 | td.objects.insert(insertidx, (*tiargs)[i - insertlen .. i]); | |
6919 | if (insertidx == 0) // reset original tuple start point | |
6920 | origstart = insertlen; | |
6921 | insertlen = 0; | |
6922 | } | |
6923 | if (insertidx) // insert tuple if found more than one time | |
6924 | { | |
6925 | td.objects.reserve(oldlen); // reserve first to assert a valid slice | |
6926 | td.objects.pushSlice((*td.objects)[origstart .. origstart + oldlen]); | |
6927 | } | |
6928 | insertidx = td.objects.length; | |
6929 | } | |
6930 | if (insertlen) | |
6931 | { | |
6932 | if (insertlen != tiargs.length) // insert any left element | |
6933 | td.objects.pushSlice((*tiargs)[$ - insertlen .. $]); | |
6934 | else | |
6935 | // just assign tiargs if tuple = AliasSeq!(nottuple, nottuple...) | |
6936 | td.objects = tempinst.tiargs; | |
6937 | } | |
6938 | return td; | |
6939 | } | |
6940 | ||
6941 | /*************************************** | |
6942 | * Check if a template instance is a trivial AliasSeq but without other overloads. | |
6943 | * We can only be 100% sure of being AliasSeq after running semanticTiargs() | |
6944 | * and findBestMatch() but this optimization must happen before that. | |
6945 | */ | |
6946 | private TemplateInstance isAliasSeq(Scope* sc, TypeInstance ti) | |
6947 | { | |
6948 | auto tovers = ti.tempinst.tempdecl.isOverloadSet(); | |
6949 | foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) | |
6950 | { | |
6951 | Dsymbol dstart = tovers ? tovers.a[oi] : ti.tempinst.tempdecl; | |
6952 | int r = overloadApply(dstart, (Dsymbol s) | |
6953 | { | |
6954 | auto td = s.isTemplateDeclaration(); | |
6955 | if (!td || !td.isTrivialAliasSeq) | |
6956 | return 1; | |
6957 | return 0; | |
6958 | }); | |
6959 | if (r) | |
6960 | return null; | |
6961 | } | |
6962 | return ti.tempinst; | |
6963 | } | |
6964 | ||
5fee5ec3 IB |
6965 | /*************************************** |
6966 | * Find all instance fields in `ad`, then push them into `fields`. | |
6967 | * | |
6968 | * Runs semantic() for all instance field variables, but also | |
6969 | * the field types can remain yet not resolved forward references, | |
6970 | * except direct recursive definitions. | |
6971 | * After the process sizeok is set to Sizeok.fwd. | |
6972 | * | |
6973 | * Params: | |
6974 | * ad = the AggregateDeclaration to examine | |
6975 | * Returns: | |
6976 | * false if any errors occur. | |
6977 | */ | |
6978 | bool determineFields(AggregateDeclaration ad) | |
6979 | { | |
6980 | if (ad._scope) | |
6981 | dsymbolSemantic(ad, null); | |
6982 | if (ad.sizeok != Sizeok.none) | |
6983 | return true; | |
6984 | ||
6985 | //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim); | |
6986 | // determineFields can be called recursively from one of the fields's v.semantic | |
6987 | ad.fields.setDim(0); | |
6988 | ||
6989 | static int func(Dsymbol s, AggregateDeclaration ad) | |
6990 | { | |
6991 | auto v = s.isVarDeclaration(); | |
6992 | if (!v) | |
6993 | return 0; | |
6994 | if (v.storage_class & STC.manifest) | |
6995 | return 0; | |
6996 | ||
6997 | if (v.semanticRun < PASS.semanticdone) | |
6998 | v.dsymbolSemantic(null); | |
6999 | // Return in case a recursive determineFields triggered by v.semantic already finished | |
7000 | if (ad.sizeok != Sizeok.none) | |
7001 | return 1; | |
7002 | ||
7003 | if (v.aliassym) | |
d97f3bca IB |
7004 | { |
7005 | // If this variable was really a tuple, process each element. | |
7006 | if (auto tup = v.aliassym.isTupleDeclaration()) | |
7007 | return tup.foreachVar(tv => tv.apply(&func, ad)); | |
7008 | return 0; | |
7009 | } | |
5fee5ec3 IB |
7010 | |
7011 | if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter)) | |
7012 | return 0; | |
7013 | if (!v.isField() || v.semanticRun < PASS.semanticdone) | |
7014 | return 1; // unresolvable forward reference | |
7015 | ||
7016 | ad.fields.push(v); | |
7017 | ||
7018 | if (v.storage_class & STC.ref_) | |
7019 | return 0; | |
7020 | auto tv = v.type.baseElemOf(); | |
7021 | if (auto tvs = tv.isTypeStruct()) | |
7022 | { | |
7023 | if (ad == tvs.sym) | |
7024 | { | |
7025 | const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : ""; | |
7026 | ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz); | |
7027 | ad.type = Type.terror; | |
7028 | ad.errors = true; | |
7029 | return 1; | |
7030 | } | |
7031 | } | |
7032 | return 0; | |
7033 | } | |
7034 | ||
7035 | if (ad.members) | |
7036 | { | |
7037 | for (size_t i = 0; i < ad.members.dim; i++) | |
7038 | { | |
7039 | auto s = (*ad.members)[i]; | |
7040 | if (s.apply(&func, ad)) | |
7041 | { | |
7042 | if (ad.sizeok != Sizeok.none) | |
7043 | { | |
7044 | // recursive determineFields already finished | |
7045 | return true; | |
7046 | } | |
7047 | return false; | |
7048 | } | |
7049 | } | |
7050 | } | |
7051 | ||
7052 | if (ad.sizeok != Sizeok.done) | |
7053 | ad.sizeok = Sizeok.fwd; | |
7054 | ||
7055 | return true; | |
7056 | } | |
fbdaa581 IB |
7057 | |
7058 | /// Do an atomic operation (currently tailored to [shared] static ctors|dtors) needs | |
7059 | private CallExp doAtomicOp (string op, Identifier var, Expression arg) | |
7060 | { | |
7061 | __gshared Import imp = null; | |
7062 | __gshared Identifier[1] id; | |
7063 | ||
7064 | assert(op == "-=" || op == "+="); | |
7065 | ||
7066 | const loc = Loc.initial; | |
7067 | ||
7068 | // Below code is similar to `loadStdMath` (used for `^^` operator) | |
7069 | if (!imp) | |
7070 | { | |
7071 | id[0] = Id.core; | |
7072 | auto s = new Import(Loc.initial, id[], Id.atomic, null, true); | |
7073 | // Module.load will call fatal() if there's no std.math available. | |
7074 | // Gag the error here, pushing the error handling to the caller. | |
7075 | uint errors = global.startGagging(); | |
7076 | s.load(null); | |
7077 | if (s.mod) | |
7078 | { | |
7079 | s.mod.importAll(null); | |
7080 | s.mod.dsymbolSemantic(null); | |
7081 | } | |
7082 | global.endGagging(errors); | |
7083 | imp = s; | |
7084 | } | |
7085 | // Module couldn't be loaded | |
7086 | if (imp.mod is null) | |
7087 | return null; | |
7088 | ||
7089 | Objects* tiargs = new Objects(1); | |
7090 | (*tiargs)[0] = new StringExp(loc, op); | |
7091 | ||
7092 | Expressions* args = new Expressions(2); | |
7093 | (*args)[0] = new IdentifierExp(loc, var); | |
7094 | (*args)[1] = arg; | |
7095 | ||
7096 | auto sc = new ScopeExp(loc, imp.mod); | |
7097 | auto dti = new DotTemplateInstanceExp( | |
7098 | loc, sc, Id.atomicOp, tiargs); | |
7099 | ||
7100 | return CallExp.create(loc, dti, args); | |
7101 | } |