1 /**
2 * Performs the semantic2 stage, which deals with initializer expressions.
3 *
4 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d)
8 * Documentation: https://dlang.org/phobos/dmd_semantic2.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic2.d
10 */
11
12 module dmd.semantic2;
13
14 import core.stdc.stdio;
15 import core.stdc.string;
16
17 import dmd.aggregate;
18 import dmd.aliasthis;
19 import dmd.arraytypes;
20 import dmd.astcodegen;
21 import dmd.astenums;
22 import dmd.attrib;
23 import dmd.blockexit;
24 import dmd.clone;
25 import dmd.dcast;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.denum;
29 import dmd.dimport;
30 import dmd.dinterpret;
31 import dmd.dmodule;
32 import dmd.dscope;
33 import dmd.dstruct;
34 import dmd.dsymbol;
35 import dmd.dsymbolsem;
36 import dmd.dtemplate;
37 import dmd.dversion;
38 import dmd.errors;
39 import dmd.escape;
40 import dmd.expression;
41 import dmd.expressionsem;
42 import dmd.func;
43 import dmd.globals;
44 import dmd.id;
45 import dmd.identifier;
46 import dmd.init;
47 import dmd.initsem;
48 import dmd.hdrgen;
49 import dmd.mtype;
50 import dmd.nogc;
51 import dmd.nspace;
52 import dmd.objc;
53 import dmd.opover;
54 import dmd.parse;
55 import dmd.root.filename;
56 import dmd.common.outbuffer;
57 import dmd.root.rmem;
58 import dmd.root.rootobject;
59 import dmd.root.utf;
60 import dmd.sideeffect;
61 import dmd.statementsem;
62 import dmd.staticassert;
63 import dmd.tokens;
64 import dmd.statement;
65 import dmd.target;
66 import dmd.templateparamsem;
67 import dmd.typesem;
68 import dmd.visitor;
69
70 enum LOG = false;
71
72
73 /*************************************
74 * Does semantic analysis on initializers and members of aggregates.
75 */
semantic2(Dsymbol dsym,Scope * sc)76 extern(C++) void semantic2(Dsymbol dsym, Scope* sc)
77 {
78 scope v = new Semantic2Visitor(sc);
79 dsym.accept(v);
80 }
81
82 private extern(C++) final class Semantic2Visitor : Visitor
83 {
84 alias visit = Visitor.visit;
85 Scope* sc;
this(Scope * sc)86 this(Scope* sc)
87 {
88 this.sc = sc;
89 }
90
visit(Dsymbol)91 override void visit(Dsymbol) {}
92
visit(StaticAssert sa)93 override void visit(StaticAssert sa)
94 {
95 //printf("StaticAssert::semantic2() %s\n", sa.toChars());
96 auto sds = new ScopeDsymbol();
97 sc = sc.push(sds);
98 sc.tinst = null;
99 sc.minst = null;
100
101 import dmd.staticcond;
102 bool errors;
103 bool result = evalStaticCondition(sc, sa.exp, sa.exp, errors);
104 sc = sc.pop();
105 if (errors)
106 {
107 errorSupplemental(sa.loc, "while evaluating: `static assert(%s)`", sa.exp.toChars());
108 return;
109 }
110 else if (result)
111 return;
112
113 if (sa.msg)
114 {
115 sc = sc.startCTFE();
116 sa.msg = sa.msg.expressionSemantic(sc);
117 sa.msg = resolveProperties(sc, sa.msg);
118 sc = sc.endCTFE();
119 sa.msg = sa.msg.ctfeInterpret();
120 if (StringExp se = sa.msg.toStringExp())
121 {
122 // same with pragma(msg)
123 const slice = se.toUTF8(sc).peekString();
124 error(sa.loc, "static assert: \"%.*s\"", cast(int)slice.length, slice.ptr);
125 }
126 else
127 error(sa.loc, "static assert: %s", sa.msg.toChars());
128 }
129 else
130 error(sa.loc, "static assert: `%s` is false", sa.exp.toChars());
131 if (sc.tinst)
132 sc.tinst.printInstantiationTrace();
133 if (!global.gag)
134 fatal();
135 }
136
visit(TemplateInstance tempinst)137 override void visit(TemplateInstance tempinst)
138 {
139 if (tempinst.semanticRun >= PASS.semantic2)
140 return;
141 tempinst.semanticRun = PASS.semantic2;
142 static if (LOG)
143 {
144 printf("+TemplateInstance.semantic2('%s')\n", tempinst.toChars());
145 scope(exit) printf("-TemplateInstance.semantic2('%s')\n", tempinst.toChars());
146 }
147 if (tempinst.errors || !tempinst.members)
148 return;
149
150 TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
151 assert(tempdecl);
152
153 sc = tempdecl._scope;
154 assert(sc);
155 sc = sc.push(tempinst.argsym);
156 sc = sc.push(tempinst);
157 sc.tinst = tempinst;
158 sc.minst = tempinst.minst;
159
160 int needGagging = (tempinst.gagged && !global.gag);
161 uint olderrors = global.errors;
162 int oldGaggedErrors = -1; // dead-store to prevent spurious warning
163 if (needGagging)
164 oldGaggedErrors = global.startGagging();
165
166 for (size_t i = 0; i < tempinst.members.dim; i++)
167 {
168 Dsymbol s = (*tempinst.members)[i];
169 static if (LOG)
170 {
171 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
172 }
173 s.semantic2(sc);
174 if (tempinst.gagged && global.errors != olderrors)
175 break;
176 }
177
178 if (global.errors != olderrors)
179 {
180 if (!tempinst.errors)
181 {
182 if (!tempdecl.literal)
183 tempinst.error(tempinst.loc, "error instantiating");
184 if (tempinst.tinst)
185 tempinst.tinst.printInstantiationTrace();
186 }
187 tempinst.errors = true;
188 }
189 if (needGagging)
190 global.endGagging(oldGaggedErrors);
191
192 sc = sc.pop();
193 sc.pop();
194 }
195
visit(TemplateMixin tmix)196 override void visit(TemplateMixin tmix)
197 {
198 if (tmix.semanticRun >= PASS.semantic2)
199 return;
200 tmix.semanticRun = PASS.semantic2;
201 static if (LOG)
202 {
203 printf("+TemplateMixin.semantic2('%s')\n", tmix.toChars());
204 scope(exit) printf("-TemplateMixin.semantic2('%s')\n", tmix.toChars());
205 }
206 if (!tmix.members)
207 return;
208
209 assert(sc);
210 sc = sc.push(tmix.argsym);
211 sc = sc.push(tmix);
212 sc.tinst = tmix;
213 sc.minst = tmix.minst;
214 for (size_t i = 0; i < tmix.members.dim; i++)
215 {
216 Dsymbol s = (*tmix.members)[i];
217 static if (LOG)
218 {
219 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
220 }
221 s.semantic2(sc);
222 }
223 sc = sc.pop();
224 sc.pop();
225 }
226
visit(VarDeclaration vd)227 override void visit(VarDeclaration vd)
228 {
229 if (vd.semanticRun < PASS.semanticdone && vd.inuse)
230 return;
231
232 //printf("VarDeclaration::semantic2('%s')\n", toChars());
233
234 if (vd.aliassym) // if it's a tuple
235 {
236 vd.aliassym.accept(this);
237 vd.semanticRun = PASS.semantic2done;
238 return;
239 }
240
241 UserAttributeDeclaration.checkGNUABITag(vd, vd._linkage);
242
243 if (vd._init && !vd.toParent().isFuncDeclaration())
244 {
245 vd.inuse++;
246
247 /* https://issues.dlang.org/show_bug.cgi?id=20280
248 *
249 * Template instances may import modules that have not
250 * finished semantic1.
251 */
252 if (!vd.type)
253 vd.dsymbolSemantic(sc);
254
255
256 // https://issues.dlang.org/show_bug.cgi?id=14166
257 // https://issues.dlang.org/show_bug.cgi?id=20417
258 // Don't run CTFE for the temporary variables inside typeof or __traits(compiles)
259 vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret);
260 vd.inuse--;
261 }
262 if (vd._init && vd.storage_class & STC.manifest)
263 {
264 /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
265 * Scan initializer looking for them. Issue error if found.
266 */
267 if (ExpInitializer ei = vd._init.isExpInitializer())
268 {
269 static bool hasInvalidEnumInitializer(Expression e)
270 {
271 static bool arrayHasInvalidEnumInitializer(Expressions* elems)
272 {
273 foreach (e; *elems)
274 {
275 if (e && hasInvalidEnumInitializer(e))
276 return true;
277 }
278 return false;
279 }
280
281 if (e.op == EXP.classReference)
282 return true;
283 if (e.op == EXP.address && (cast(AddrExp)e).e1.op == EXP.structLiteral)
284 return true;
285 if (e.op == EXP.arrayLiteral)
286 return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements);
287 if (e.op == EXP.structLiteral)
288 return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
289 if (e.op == EXP.assocArrayLiteral)
290 {
291 AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
292 return arrayHasInvalidEnumInitializer(ae.values) ||
293 arrayHasInvalidEnumInitializer(ae.keys);
294 }
295 return false;
296 }
297
298 if (hasInvalidEnumInitializer(ei.exp))
299 vd.error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
300 }
301 }
302 else if (vd._init && vd.isThreadlocal())
303 {
304 // Cannot initialize a thread-local class or pointer to struct variable with a literal
305 // that itself is a thread-local reference and would need dynamic initialization also.
306 if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
307 {
308 ExpInitializer ei = vd._init.isExpInitializer();
309 if (ei && ei.exp.op == EXP.classReference)
310 vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.");
311 }
312 else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared())
313 {
314 ExpInitializer ei = vd._init.isExpInitializer();
315 if (ei && ei.exp.op == EXP.address && (cast(AddrExp)ei.exp).e1.op == EXP.structLiteral)
316 vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.");
317 }
318 }
319 vd.semanticRun = PASS.semantic2done;
320 }
321
visit(Module mod)322 override void visit(Module mod)
323 {
324 //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
325 if (mod.semanticRun != PASS.semanticdone) // semantic() not completed yet - could be recursive call
326 return;
327 mod.semanticRun = PASS.semantic2;
328 // Note that modules get their own scope, from scratch.
329 // This is so regardless of where in the syntax a module
330 // gets imported, it is unaffected by context.
331 Scope* sc = Scope.createGlobal(mod); // create root scope
332 //printf("Module = %p\n", sc.scopesym);
333 if (mod.members)
334 {
335 // Pass 2 semantic routines: do initializers and function bodies
336 for (size_t i = 0; i < mod.members.dim; i++)
337 {
338 Dsymbol s = (*mod.members)[i];
339 s.semantic2(sc);
340 }
341 }
342 if (mod.userAttribDecl)
343 {
344 mod.userAttribDecl.semantic2(sc);
345 }
346 sc = sc.pop();
347 sc.pop();
348 mod.semanticRun = PASS.semantic2done;
349 //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
350 }
351
visit(FuncDeclaration fd)352 override void visit(FuncDeclaration fd)
353 {
354 if (fd.semanticRun >= PASS.semantic2done)
355 return;
356
357 if (fd.semanticRun < PASS.semanticdone && !fd.errors)
358 {
359 /* https://issues.dlang.org/show_bug.cgi?id=21614
360 *
361 * Template instances may import modules that have not
362 * finished semantic1.
363 */
364 fd.dsymbolSemantic(sc);
365 }
366 assert(fd.semanticRun <= PASS.semantic2);
367 fd.semanticRun = PASS.semantic2;
368
369 //printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr);
370
371 // Only check valid functions which have a body to avoid errors
372 // for multiple declarations, e.g.
373 // void foo();
374 // void foo();
375 if (fd.fbody && fd.overnext && !fd.errors)
376 {
377 // Always starts the lookup from 'this', because the conflicts with
378 // previous overloads are already reported.
379 alias f1 = fd;
380 auto tf1 = cast(TypeFunction) f1.type;
381 auto parent1 = f1.toParent2();
382 const linkage1 = f1.resolvedLinkage();
383
384 overloadApply(f1, (Dsymbol s)
385 {
386 auto f2 = s.isFuncDeclaration();
387 if (!f2 || f1 == f2 || f2.errors)
388 return 0;
389
390 // Don't have to check conflict between declaration and definition.
391 if (f2.fbody is null)
392 return 0;
393
394 // Functions with different manglings can never conflict
395 if (linkage1 != f2.resolvedLinkage())
396 return 0;
397
398 // Functions with different names never conflict
399 // (they can form overloads sets introduced by an alias)
400 if (f1.ident != f2.ident)
401 return 0;
402
403 // Functions with different parents never conflict
404 // (E.g. when aliasing a free function into a struct)
405 if (parent1 != f2.toParent2())
406 return 0;
407
408 /* Check for overload merging with base class member functions.
409 *
410 * class B { void foo() {} }
411 * class D : B {
412 * override void foo() {} // B.foo appears as f2
413 * alias foo = B.foo;
414 * }
415 */
416 if (f1.overrides(f2))
417 return 0;
418
419 auto tf2 = cast(TypeFunction) f2.type;
420
421 // Overloading based on storage classes
422 if (tf1.mod != tf2.mod || ((f1.storage_class ^ f2.storage_class) & STC.static_))
423 return 0;
424
425 const sameAttr = tf1.attributesEqual(tf2);
426 const sameParams = tf1.parameterList == tf2.parameterList;
427
428 // Allow the hack to declare overloads with different parameters/STC's
429 // @@@DEPRECATED_2.104@@@
430 // Deprecated in 2020-08, make this an error in 2.104
431 if (parent1.isModule() &&
432 linkage1 != LINK.d && linkage1 != LINK.cpp &&
433 (!sameAttr || !sameParams)
434 )
435 {
436 f2.deprecation("cannot overload `extern(%s)` function at %s",
437 linkageToChars(f1._linkage),
438 f1.loc.toChars());
439 return 0;
440 }
441
442 // Different parameters don't conflict in extern(C++/D)
443 if (!sameParams)
444 return 0;
445
446 // Different attributes don't conflict in extern(D)
447 if (!sameAttr && linkage1 == LINK.d)
448 return 0;
449
450 error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s",
451 f2.kind(),
452 f2.toPrettyChars(),
453 parametersTypeToChars(tf2.parameterList),
454 f1.loc.toChars());
455 f2.type = Type.terror;
456 f2.errors = true;
457 return 0;
458 });
459 }
460 if (!fd.type || fd.type.ty != Tfunction)
461 return;
462 TypeFunction f = cast(TypeFunction) fd.type;
463
464 UserAttributeDeclaration.checkGNUABITag(fd, fd._linkage);
465 //semantic for parameters' UDAs
466 foreach (i, param; f.parameterList)
467 {
468 if (param && param.userAttribDecl)
469 param.userAttribDecl.semantic2(sc);
470 }
471 }
472
visit(Import i)473 override void visit(Import i)
474 {
475 //printf("Import::semantic2('%s')\n", toChars());
476 if (!i.mod)
477 return;
478
479 i.mod.semantic2(null);
480 if (i.mod.needmoduleinfo)
481 {
482 //printf("module5 %s because of %s\n", sc._module.toChars(), mod.toChars());
483 if (sc)
484 sc._module.needmoduleinfo = 1;
485 }
486 }
487
visit(Nspace ns)488 override void visit(Nspace ns)
489 {
490 if (ns.semanticRun >= PASS.semantic2)
491 return;
492 ns.semanticRun = PASS.semantic2;
493 static if (LOG)
494 {
495 printf("+Nspace::semantic2('%s')\n", ns.toChars());
496 scope(exit) printf("-Nspace::semantic2('%s')\n", ns.toChars());
497 }
498 UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
499 if (!ns.members)
500 return;
501
502 assert(sc);
503 sc = sc.push(ns);
504 sc.linkage = LINK.cpp;
505 foreach (s; *ns.members)
506 {
507 static if (LOG)
508 {
509 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
510 }
511 s.semantic2(sc);
512 }
513 sc.pop();
514 }
515
visit(AttribDeclaration ad)516 override void visit(AttribDeclaration ad)
517 {
518 Dsymbols* d = ad.include(sc);
519 if (!d)
520 return;
521
522 Scope* sc2 = ad.newScope(sc);
523 for (size_t i = 0; i < d.dim; i++)
524 {
525 Dsymbol s = (*d)[i];
526 s.semantic2(sc2);
527 }
528 if (sc2 != sc)
529 sc2.pop();
530 }
531
532 /**
533 * Run the DeprecatedDeclaration's semantic2 phase then its members.
534 *
535 * The message set via a `DeprecatedDeclaration` can be either of:
536 * - a string literal
537 * - an enum
538 * - a static immutable
539 * So we need to call ctfe to resolve it.
540 * Afterward forwards to the members' semantic2.
541 */
visit(DeprecatedDeclaration dd)542 override void visit(DeprecatedDeclaration dd)
543 {
544 getMessage(dd);
545 visit(cast(AttribDeclaration)dd);
546 }
547
visit(AlignDeclaration ad)548 override void visit(AlignDeclaration ad)
549 {
550 ad.getAlignment(sc);
551 visit(cast(AttribDeclaration)ad);
552 }
553
visit(CPPNamespaceDeclaration decl)554 override void visit(CPPNamespaceDeclaration decl)
555 {
556 UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp);
557 visit(cast(AttribDeclaration)decl);
558 }
559
visit(UserAttributeDeclaration uad)560 override void visit(UserAttributeDeclaration uad)
561 {
562 if (!uad.decl || !uad.atts || !uad.atts.dim || !uad._scope)
563 return visit(cast(AttribDeclaration)uad);
564
565 Expression* lastTag;
566 static void eval(Scope* sc, Expressions* exps, ref Expression* lastTag)
567 {
568 foreach (ref Expression e; *exps)
569 {
570 if (!e)
571 continue;
572
573 e = e.expressionSemantic(sc);
574 if (definitelyValueParameter(e))
575 e = e.ctfeInterpret();
576 if (e.op == EXP.tuple)
577 {
578 TupleExp te = cast(TupleExp)e;
579 eval(sc, te.exps, lastTag);
580 }
581
582 // Handles compiler-recognized `core.attribute.gnuAbiTag`
583 if (UserAttributeDeclaration.isGNUABITag(e))
584 doGNUABITagSemantic(e, lastTag);
585 }
586 }
587
588 uad._scope = null;
589 eval(sc, uad.atts, lastTag);
590 visit(cast(AttribDeclaration)uad);
591 }
592
visit(AggregateDeclaration ad)593 override void visit(AggregateDeclaration ad)
594 {
595 //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", ad.toChars(), ad.type.toChars(), ad.errors);
596 if (!ad.members)
597 return;
598
599 if (ad._scope)
600 {
601 ad.error("has forward references");
602 return;
603 }
604
605 UserAttributeDeclaration.checkGNUABITag(
606 ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
607
608 auto sc2 = ad.newScope(sc);
609
610 ad.determineSize(ad.loc);
611
612 for (size_t i = 0; i < ad.members.dim; i++)
613 {
614 Dsymbol s = (*ad.members)[i];
615 //printf("\t[%d] %s\n", i, s.toChars());
616 s.semantic2(sc2);
617 }
618
619 sc2.pop();
620 }
621
visit(ClassDeclaration cd)622 override void visit(ClassDeclaration cd)
623 {
624 /// Checks that the given class implements all methods of its interfaces.
625 static void checkInterfaceImplementations(ClassDeclaration cd)
626 {
627 foreach (base; cd.interfaces)
628 {
629 // first entry is ClassInfo reference
630 auto methods = base.sym.vtbl[base.sym.vtblOffset .. $];
631
632 foreach (m; methods)
633 {
634 auto ifd = m.isFuncDeclaration;
635 assert(ifd);
636
637 if (ifd.objc.isOptional)
638 continue;
639
640 auto type = ifd.type.toTypeFunction();
641 auto fd = cd.findFunc(ifd.ident, type);
642
643 if (fd && !fd.isAbstract)
644 {
645 //printf(" found\n");
646 // Check that calling conventions match
647 if (fd._linkage != ifd._linkage)
648 fd.error("linkage doesn't match interface function");
649
650 // Check that it is current
651 //printf("newinstance = %d fd.toParent() = %s ifd.toParent() = %s\n",
652 //newinstance, fd.toParent().toChars(), ifd.toParent().toChars());
653 if (fd.toParent() != cd && ifd.toParent() == base.sym)
654 cd.error("interface function `%s` is not implemented", ifd.toFullSignature());
655 }
656 else
657 {
658 //printf(" not found %p\n", fd);
659 // BUG: should mark this class as abstract?
660 if (!cd.isAbstract())
661 cd.error("interface function `%s` is not implemented", ifd.toFullSignature());
662 }
663 }
664 }
665 }
666
667 if (cd.semanticRun >= PASS.semantic2done)
668 return;
669 assert(cd.semanticRun <= PASS.semantic2);
670 cd.semanticRun = PASS.semantic2;
671
672 checkInterfaceImplementations(cd);
673 visit(cast(AggregateDeclaration) cd);
674 }
675
visit(InterfaceDeclaration cd)676 override void visit(InterfaceDeclaration cd)
677 {
678 visit(cast(AggregateDeclaration) cd);
679 }
680
visit(TupleDeclaration td)681 override void visit(TupleDeclaration td)
682 {
683 td.foreachVar((s) { s.accept(this); });
684 }
685 }
686
687 /**
688 * Perform semantic analysis specific to the GNU ABI tags
689 *
690 * The GNU ABI tags are a feature introduced in C++11, specific to g++
691 * and the Itanium ABI.
692 * They are mandatory for C++ interfacing, simply because the templated struct
693 *`std::basic_string`, of which the ubiquitous `std::string` is a instantiation
694 * of, uses them.
695 *
696 * Params:
697 * e = Expression to perform semantic on
698 * See `Semantic2Visitor.visit(UserAttributeDeclaration)`
699 * lastTag = When `!is null`, we already saw an ABI tag.
700 * To simplify implementation and reflection code,
701 * only one ABI tag object is allowed per symbol
702 * (but it can have multiple tags as it's an array exp).
703 */
doGNUABITagSemantic(ref Expression e,ref Expression * lastTag)704 private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
705 {
706 import dmd.dmangle;
707
708 // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
709 if (e.op == EXP.type)
710 {
711 e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
712 return;
713 }
714
715 // Definition is in `core.attributes`. If it's not a struct literal,
716 // it shouldn't have passed semantic, hence the `assert`.
717 auto sle = e.isStructLiteralExp();
718 if (sle is null)
719 {
720 assert(global.errors);
721 return;
722 }
723 // The definition of `gnuAttributes` only have 1 member, `string[] tags`
724 assert(sle.elements && sle.elements.length == 1);
725 // `gnuAbiTag`'s constructor is defined as `this(string[] tags...)`
726 auto ale = (*sle.elements)[0].isArrayLiteralExp();
727 if (ale is null)
728 {
729 e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
730 return;
731 }
732
733 // Check that it's the only tag on the symbol
734 if (lastTag !is null)
735 {
736 const str1 = (*lastTag.isStructLiteralExp().elements)[0].toString();
737 const str2 = ale.toString();
738 e.error("only one `@%s` allowed per symbol", Id.udaGNUAbiTag.toChars());
739 e.errorSupplemental("instead of `@%s @%s`, use `@%s(%.*s, %.*s)`",
740 lastTag.toChars(), e.toChars(), Id.udaGNUAbiTag.toChars(),
741 // Avoid [ ... ]
742 cast(int)str1.length - 2, str1.ptr + 1,
743 cast(int)str2.length - 2, str2.ptr + 1);
744 return;
745 }
746 lastTag = &e;
747
748 // We already know we have a valid array literal of strings.
749 // Now checks that elements are valid.
750 foreach (idx, elem; *ale.elements)
751 {
752 const str = elem.toStringExp().peekString();
753 if (!str.length)
754 {
755 e.error("argument `%d` to `@%s` cannot be %s", cast(int)(idx + 1),
756 Id.udaGNUAbiTag.toChars(),
757 elem.isNullExp() ? "`null`".ptr : "empty".ptr);
758 continue;
759 }
760
761 foreach (c; str)
762 {
763 if (!c.isValidMangling())
764 {
765 e.error("`@%s` char `0x%02x` not allowed in mangling",
766 Id.udaGNUAbiTag.toChars(), c);
767 break;
768 }
769 }
770 // Valid element
771 }
772 // Since ABI tags need to be sorted, we sort them in place
773 // It might be surprising for users that inspects the UDAs,
774 // but it's a concession to practicality.
775 // Casts are unfortunately necessary as `implicitConvTo` is not
776 // `const` (and nor is `StringExp`, by extension).
777 static int predicate(const scope Expression* e1, const scope Expression* e2) nothrow
778 {
779 scope(failure) assert(0, "An exception was thrown");
780 return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp());
781 }
782 ale.elements.sort!predicate;
783 }
784