]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/func.d
Merge dmd, druntime ceff48bf7d, phobos dcbfbd43a
[thirdparty/gcc.git] / gcc / d / dmd / func.d
1 /**
2 * Defines a function declaration.
3 *
4 * Includes:
5 * - function/delegate literals
6 * - function aliases
7 * - (static/shared) constructors/destructors/post-blits
8 * - `invariant`
9 * - `unittest`
10 *
11 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15 * Documentation: https://dlang.org/phobos/dmd_func.html
16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
17 */
18
19 module dmd.func;
20
21 import core.stdc.stdio;
22 import core.stdc.string;
23 import dmd.aggregate;
24 import dmd.arraytypes;
25 import dmd.astenums;
26 import dmd.blockexit;
27 import dmd.gluelayer;
28 import dmd.dcast;
29 import dmd.dclass;
30 import dmd.declaration;
31 import dmd.delegatize;
32 import dmd.dinterpret;
33 import dmd.dmodule;
34 import dmd.dscope;
35 import dmd.dstruct;
36 import dmd.dsymbol;
37 import dmd.dsymbolsem;
38 import dmd.dtemplate;
39 import dmd.errors;
40 import dmd.escape;
41 import dmd.expression;
42 import dmd.funcsem;
43 import dmd.globals;
44 import dmd.hdrgen;
45 import dmd.id;
46 import dmd.identifier;
47 import dmd.init;
48 import dmd.location;
49 import dmd.mtype;
50 import dmd.objc;
51 import dmd.root.aav;
52 import dmd.common.outbuffer;
53 import dmd.rootobject;
54 import dmd.root.string;
55 import dmd.root.stringtable;
56 import dmd.semantic2;
57 import dmd.semantic3;
58 import dmd.statement_rewrite_walker;
59 import dmd.statement;
60 import dmd.statementsem;
61 import dmd.tokens;
62 import dmd.typesem;
63 import dmd.visitor;
64
65 version (IN_GCC) {}
66 else version (IN_LLVM) {}
67 else version = MARS;
68
69 /// Inline Status
70 enum ILS : ubyte
71 {
72 uninitialized, /// not computed yet
73 no, /// cannot inline
74 yes, /// can inline
75 }
76
77 enum BUILTIN : ubyte
78 {
79 unknown = 255, /// not known if this is a builtin
80 unimp = 0, /// this is not a builtin
81 gcc, /// this is a GCC builtin
82 llvm, /// this is an LLVM builtin
83 sin,
84 cos,
85 tan,
86 sqrt,
87 fabs,
88 ldexp,
89 log,
90 log2,
91 log10,
92 exp,
93 expm1,
94 exp2,
95 round,
96 floor,
97 ceil,
98 trunc,
99 copysign,
100 pow,
101 fmin,
102 fmax,
103 fma,
104 isnan,
105 isinfinity,
106 isfinite,
107 bsf,
108 bsr,
109 bswap,
110 popcnt,
111 yl2x,
112 yl2xp1,
113 toPrecFloat,
114 toPrecDouble,
115 toPrecReal
116 }
117
118 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
119 */
120 extern (C++) final class NrvoWalker : StatementRewriteWalker
121 {
122 alias visit = typeof(super).visit;
123 public:
124 FuncDeclaration fd;
125 Scope* sc;
126
127 override void visit(ReturnStatement s)
128 {
129 // See if all returns are instead to be replaced with a goto returnLabel;
130 if (fd.returnLabel)
131 {
132 /* Rewrite:
133 * return exp;
134 * as:
135 * vresult = exp; goto Lresult;
136 */
137 auto gs = new GotoStatement(s.loc, Id.returnLabel);
138 gs.label = fd.returnLabel;
139
140 Statement s1 = gs;
141 if (s.exp)
142 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
143
144 replaceCurrent(s1);
145 }
146 }
147
148 override void visit(TryFinallyStatement s)
149 {
150 DtorExpStatement des;
151 if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
152 fd.nrvo_var == des.var)
153 {
154 if (!(global.params.useExceptions && ClassDeclaration.throwable))
155 {
156 /* Don't need to call destructor at all, since it is nrvo
157 */
158 replaceCurrent(s._body);
159 s._body.accept(this);
160 return;
161 }
162
163 /* Normally local variable dtors are called regardless exceptions.
164 * But for nrvo_var, its dtor should be called only when exception is thrown.
165 *
166 * Rewrite:
167 * try { s.body; } finally { nrvo_var.edtor; }
168 * // equivalent with:
169 * // s.body; scope(exit) nrvo_var.edtor;
170 * as:
171 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
172 * // equivalent with:
173 * // s.body; scope(failure) nrvo_var.edtor;
174 */
175 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
176 Identifier id = Identifier.generateId("__o");
177
178 Statement handler = new PeelStatement(sexception);
179 if (sexception.blockExit(fd, null) & BE.fallthru)
180 {
181 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
182 ts.internalThrow = true;
183 handler = new CompoundStatement(Loc.initial, handler, ts);
184 }
185
186 auto catches = new Catches();
187 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
188 ctch.internalCatch = true;
189 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
190 catches.push(ctch);
191
192 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
193 fd.hasNoEH = false;
194 replaceCurrent(s2);
195 s2.accept(this);
196 }
197 else
198 StatementRewriteWalker.visit(s);
199 }
200 }
201
202 private struct FUNCFLAG
203 {
204 bool purityInprocess; /// working on determining purity
205 bool safetyInprocess; /// working on determining safety
206 bool nothrowInprocess; /// working on determining nothrow
207 bool nogcInprocess; /// working on determining @nogc
208 bool returnInprocess; /// working on inferring 'return' for parameters
209 bool inlineScanned; /// function has been scanned for inline possibilities
210 bool inferScope; /// infer 'scope' for parameters
211 bool hasCatches; /// function has try-catch statements
212 bool skipCodegen; /// do not generate code for this function.
213 bool printf; /// is a printf-like function
214
215 bool scanf; /// is a scanf-like function
216 bool noreturn; /// the function does not return
217 bool isNRVO = true; /// Support for named return value optimization
218 bool isNaked; /// The function is 'naked' (see inline ASM)
219 bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
220 bool isIntroducing; /// If this function introduces the overload set
221 bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
222 bool hasNoEH; /// No exception unwinding is needed
223 bool inferRetType; /// Return type is to be inferred
224 bool hasDualContext; /// has a dual-context 'this' parameter
225
226 bool hasAlwaysInlines; /// Contains references to functions that must be inlined
227 bool isCrtCtor; /// Has attribute pragma(crt_constructor)
228 bool isCrtDtor; /// Has attribute pragma(crt_destructor)
229 bool hasEscapingSiblings;/// Has sibling functions that escape
230 bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
231 bool dllImport; /// __declspec(dllimport)
232 bool dllExport; /// __declspec(dllexport)
233 }
234
235 /***********************************************************
236 * Tuple of result identifier (possibly null) and statement.
237 * This is used to store out contracts: out(id){ ensure }
238 */
239 extern (C++) struct Ensure
240 {
241 Identifier id;
242 Statement ensure;
243
244 Ensure syntaxCopy()
245 {
246 return Ensure(id, ensure.syntaxCopy());
247 }
248
249 /*****************************************
250 * Do syntax copy of an array of Ensure's.
251 */
252 static Ensures* arraySyntaxCopy(Ensures* a)
253 {
254 Ensures* b = null;
255 if (a)
256 {
257 b = a.copy();
258 foreach (i, e; *a)
259 {
260 (*b)[i] = e.syntaxCopy();
261 }
262 }
263 return b;
264 }
265
266 }
267
268 /***********************************************************
269 * Most functions don't have contracts, so save memory by grouping
270 * this information into a separate struct
271 */
272 private struct ContractInfo
273 {
274 Statements* frequires; /// in contracts
275 Ensures* fensures; /// out contracts
276 Statement frequire; /// lowered in contract
277 Statement fensure; /// lowered out contract
278 FuncDeclaration fdrequire; /// function that does the in contract
279 FuncDeclaration fdensure; /// function that does the out contract
280 Expressions* fdrequireParams; /// argument list for __require
281 Expressions* fdensureParams; /// argument list for __ensure
282 }
283
284 /***********************************************************
285 */
286 extern (C++) class FuncDeclaration : Declaration
287 {
288 Statement fbody; /// function body
289
290 FuncDeclarations foverrides; /// functions this function overrides
291
292 private ContractInfo* contracts; /// contract information
293
294 const(char)* mangleString; /// mangled symbol created from mangleExact()
295
296 VarDeclaration vresult; /// result variable for out contracts
297 LabelDsymbol returnLabel; /// where the return goes
298
299 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
300
301 // used to prevent symbols in different
302 // scopes from having the same name
303 DsymbolTable localsymtab;
304 VarDeclaration vthis; /// 'this' parameter (member and nested)
305 VarDeclaration v_arguments; /// '_arguments' parameter
306
307 VarDeclaration v_argptr; /// '_argptr' variable
308 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
309 DsymbolTable labtab; /// statement label symbol table
310 Dsymbol overnext; /// next in overload list
311 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
312 Loc endloc; /// location of closing curly bracket
313 int vtblIndex = -1; /// for member functions, index into vtbl[]
314
315 ILS inlineStatusStmt = ILS.uninitialized;
316 ILS inlineStatusExp = ILS.uninitialized;
317 PINLINE inlining = PINLINE.default_;
318
319 int inlineNest; /// !=0 if nested inline
320
321 ForeachStatement fes; /// if foreach body, this is the foreach
322 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
323 /** if !=NULL, then this is the type
324 of the 'introducing' function
325 this one is overriding
326 */
327 Type tintro;
328
329 StorageClass storage_class2; /// storage class for template onemember's
330
331 // Things that should really go into Scope
332
333 /// 1 if there's a return exp; statement
334 /// 2 if there's a throw statement
335 /// 4 if there's an assert(0)
336 /// 8 if there's inline asm
337 /// 16 if there are multiple return statements
338 int hasReturnExp;
339
340 VarDeclaration nrvo_var; /// variable to replace with shidden
341 Symbol* shidden; /// hidden pointer passed to function
342
343 ReturnStatements* returns;
344
345 GotoStatements* gotos; /// Gotos with forward references
346
347 version (MARS)
348 {
349 VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
350 Symbol* salignSection; /// pointer to aligned section, if any
351 }
352
353 /// set if this is a known, builtin function we can evaluate at compile time
354 BUILTIN builtin = BUILTIN.unknown;
355
356 /// set if someone took the address of this function
357 int tookAddressOf;
358
359 bool requiresClosure; // this function needs a closure
360
361 /** local variables in this function which are referenced by nested functions
362 * (They'll get put into the "closure" for this function.)
363 */
364 VarDeclarations closureVars;
365
366 /** Outer variables which are referenced by this nested function
367 * (the inverse of closureVars)
368 */
369 VarDeclarations outerVars;
370
371 /// Sibling nested functions which called this one
372 FuncDeclarations siblingCallers;
373
374 FuncDeclarations *inlinedNestedCallees;
375
376 /// In case of failed `@safe` inference, store the error that made the function `@system` for
377 /// better diagnostics
378 AttributeViolation* safetyViolation;
379 AttributeViolation* nogcViolation;
380 AttributeViolation* pureViolation;
381 AttributeViolation* nothrowViolation;
382
383 /// See the `FUNCFLAG` struct
384 import dmd.common.bitfields;
385 mixin(generateBitFields!(FUNCFLAG, uint));
386
387 /**
388 * Data for a function declaration that is needed for the Objective-C
389 * integration.
390 */
391 ObjcFuncDeclaration objc;
392
393 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
394 {
395 super(loc, ident);
396 //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
397 //.printf("storage_class = x%llx\n", storage_class);
398 this.storage_class = storage_class;
399 this.type = type;
400 if (type)
401 {
402 // Normalize storage_class, because function-type related attributes
403 // are already set in the 'type' in parsing phase.
404 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
405 }
406 this.endloc = endloc;
407 if (noreturn)
408 this.noreturn = true;
409
410 /* The type given for "infer the return type" is a TypeFunction with
411 * NULL for the return type.
412 */
413 if (type && type.nextOf() is null)
414 this.inferRetType = true;
415 }
416
417 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
418 {
419 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
420 }
421
422 final nothrow pure @safe
423 {
424 private ref ContractInfo getContracts()
425 {
426 if (!contracts)
427 contracts = new ContractInfo();
428 return *contracts;
429 }
430
431 // getters
432 inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; }
433 inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; }
434 inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; }
435 inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; }
436 inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; }
437 inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; }
438 inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; }
439 inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; }
440
441 extern (D) private static string generateContractSetter(string field, string type)
442 {
443 return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~
444 "{
445 if (!param && !contracts) return null;
446 return getContracts()." ~ field ~ " = param;
447 }";
448 }
449
450 mixin(generateContractSetter("frequires", "Statements*"));
451 mixin(generateContractSetter("fensures", "Ensures*"));
452 mixin(generateContractSetter("frequire", "Statement"));
453 mixin(generateContractSetter("fensure", "Statement"));
454 mixin(generateContractSetter("fdrequire", "FuncDeclaration"));
455 mixin(generateContractSetter("fdensure", "FuncDeclaration"));
456 mixin(generateContractSetter("fdrequireParams", "Expressions*"));
457 mixin(generateContractSetter("fdensureParams", "Expressions*"));
458 }
459
460 override FuncDeclaration syntaxCopy(Dsymbol s)
461 {
462 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
463 FuncDeclaration f = s ? cast(FuncDeclaration)s
464 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
465 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
466 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
467 f.fbody = fbody ? fbody.syntaxCopy() : null;
468 return f;
469 }
470
471 override final bool equals(const RootObject o) const
472 {
473 if (this == o)
474 return true;
475
476 if (auto s = isDsymbol(o))
477 {
478 auto fd1 = this;
479 auto fd2 = s.isFuncDeclaration();
480 if (!fd2)
481 return false;
482
483 auto fa1 = fd1.isFuncAliasDeclaration();
484 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
485
486 auto fa2 = fd2.isFuncAliasDeclaration();
487 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
488
489 if (fa1 && fa2)
490 {
491 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
492 }
493
494 bool b1 = fa1 !is null;
495 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
496 b1 = false;
497
498 bool b2 = fa2 !is null;
499 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
500 b2 = false;
501
502 if (b1 != b2)
503 return false;
504
505 return faf1.toParent().equals(faf2.toParent()) &&
506 faf1.ident.equals(faf2.ident) &&
507 faf1.type.equals(faf2.type);
508 }
509 return false;
510 }
511
512 /****************************************************
513 * Determine if 'this' overrides fd.
514 * Return !=0 if it does.
515 */
516 extern (D) final int overrides(FuncDeclaration fd)
517 {
518 int result = 0;
519 if (fd.ident == ident)
520 {
521 const cov = type.covariant(fd.type);
522 if (cov != Covariant.distinct)
523 {
524 ClassDeclaration cd1 = toParent().isClassDeclaration();
525 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
526 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
527 result = 1;
528 }
529 }
530 return result;
531 }
532
533 /****************************************************
534 * Overload this FuncDeclaration with the new one f.
535 * Return true if successful; i.e. no conflict.
536 */
537 override bool overloadInsert(Dsymbol s)
538 {
539 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
540 assert(s != this);
541 AliasDeclaration ad = s.isAliasDeclaration();
542 if (ad)
543 {
544 if (overnext)
545 return overnext.overloadInsert(ad);
546 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
547 {
548 //printf("\tad = '%s'\n", ad.type.toChars());
549 return false;
550 }
551 overnext = ad;
552 //printf("\ttrue: no conflict\n");
553 return true;
554 }
555 TemplateDeclaration td = s.isTemplateDeclaration();
556 if (td)
557 {
558 if (!td.funcroot)
559 td.funcroot = this;
560 if (overnext)
561 return overnext.overloadInsert(td);
562 overnext = td;
563 return true;
564 }
565 FuncDeclaration fd = s.isFuncDeclaration();
566 if (!fd)
567 return false;
568
569 version (none)
570 {
571 /* Disable this check because:
572 * const void foo();
573 * semantic() isn't run yet on foo(), so the const hasn't been
574 * applied yet.
575 */
576 if (type)
577 {
578 printf("type = %s\n", type.toChars());
579 printf("fd.type = %s\n", fd.type.toChars());
580 }
581 // fd.type can be NULL for overloaded constructors
582 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
583 {
584 //printf("\tfalse: conflict %s\n", kind());
585 return false;
586 }
587 }
588
589 if (overnext)
590 {
591 td = overnext.isTemplateDeclaration();
592 if (td)
593 fd.overloadInsert(td);
594 else
595 return overnext.overloadInsert(fd);
596 }
597 overnext = fd;
598 //printf("\ttrue: no conflict\n");
599 return true;
600 }
601
602 /********************************************
603 * Find function in overload list that exactly matches t.
604 */
605 extern (D) final FuncDeclaration overloadExactMatch(Type t)
606 {
607 FuncDeclaration fd;
608 overloadApply(this, (Dsymbol s)
609 {
610 auto f = s.isFuncDeclaration();
611 if (!f)
612 return 0;
613 if (f.storage_class & STC.disable)
614 return 0;
615 if (t.equals(f.type))
616 {
617 fd = f;
618 return 1;
619 }
620
621 /* Allow covariant matches, as long as the return type
622 * is just a const conversion.
623 * This allows things like pure functions to match with an impure function type.
624 */
625 if (t.ty == Tfunction)
626 {
627 auto tf = cast(TypeFunction)f.type;
628 if (tf.covariant(t) == Covariant.yes &&
629 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
630 {
631 fd = f;
632 return 1;
633 }
634 }
635 return 0;
636 });
637 return fd;
638 }
639
640 /********************************************
641 * Find function in overload list that matches to the 'this' modifier.
642 * There's four result types.
643 *
644 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
645 * Returns the function and 'hasOverloads' is set to false.
646 * eg. If 'tthis" is mutable and there's only one mutable method.
647 * 2. If there's two or more match candidates, but a candidate function will be
648 * a "better match".
649 * Returns the better match function but 'hasOverloads' is set to true.
650 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
651 * the mutable method will be a better match.
652 * 3. If there's two or more match candidates, but there's no better match,
653 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
654 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
655 * 4. If there's no candidates, it's "no match" and returns null with error report.
656 * e.g. If 'tthis' is const but there's no const methods.
657 */
658 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
659 {
660 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
661 MatchAccumulator m;
662 overloadApply(this, (Dsymbol s)
663 {
664 auto f = s.isFuncDeclaration();
665 if (!f || f == m.lastf) // skip duplicates
666 return 0;
667
668 auto tf = f.type.toTypeFunction();
669 //printf("tf = %s\n", tf.toChars());
670
671 MATCH match;
672 if (tthis) // non-static functions are preferred than static ones
673 {
674 if (f.needThis())
675 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
676 else
677 match = MATCH.constant; // keep static function in overload candidates
678 }
679 else // static functions are preferred than non-static ones
680 {
681 if (f.needThis())
682 match = MATCH.convert;
683 else
684 match = MATCH.exact;
685 }
686 if (match == MATCH.nomatch)
687 return 0;
688
689 if (match > m.last) goto LcurrIsBetter;
690 if (match < m.last) goto LlastIsBetter;
691
692 // See if one of the matches overrides the other.
693 if (m.lastf.overrides(f)) goto LlastIsBetter;
694 if (f.overrides(m.lastf)) goto LcurrIsBetter;
695
696 //printf("\tambiguous\n");
697 m.nextf = f;
698 m.count++;
699 return 0;
700
701 LlastIsBetter:
702 //printf("\tlastbetter\n");
703 m.count++; // count up
704 return 0;
705
706 LcurrIsBetter:
707 //printf("\tisbetter\n");
708 if (m.last <= MATCH.convert)
709 {
710 // clear last secondary matching
711 m.nextf = null;
712 m.count = 0;
713 }
714 m.last = match;
715 m.lastf = f;
716 m.count++; // count up
717 return 0;
718 });
719
720 if (m.count == 1) // exact match
721 {
722 hasOverloads = false;
723 }
724 else if (m.count > 1) // better or ambiguous match
725 {
726 hasOverloads = true;
727 }
728 else // no match
729 {
730 hasOverloads = true;
731 auto tf = this.type.toTypeFunction();
732 assert(tthis);
733 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
734 {
735 OutBuffer thisBuf, funcBuf;
736 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
737 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
738 .error(loc, "%smethod %s is not callable using a %sobject", kind, toPrettyChars,
739 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
740 }
741 }
742 return m.lastf;
743 }
744
745 /********************************************
746 * find function template root in overload list
747 */
748 extern (D) final TemplateDeclaration findTemplateDeclRoot()
749 {
750 FuncDeclaration f = this;
751 while (f && f.overnext)
752 {
753 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
754 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
755 if (td)
756 return td;
757 f = f.overnext.isFuncDeclaration();
758 }
759 return null;
760 }
761
762 /********************************************
763 * Returns true if function was declared
764 * directly or indirectly in a unittest block
765 */
766 final bool inUnittest()
767 {
768 Dsymbol f = this;
769 do
770 {
771 if (f.isUnitTestDeclaration())
772 return true;
773 f = f.toParent();
774 }
775 while (f);
776 return false;
777 }
778
779 /*************************************
780 * Determine partial specialization order of functions `f` vs `g`.
781 * This is very similar to TemplateDeclaration::leastAsSpecialized().
782 * Params:
783 * f = first function
784 * g = second function
785 * names = names of parameters
786 * Returns:
787 * match 'this' is at least as specialized as g
788 * 0 g is more specialized than 'this'
789 */
790 static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
791 {
792 enum LOG_LEASTAS = 0;
793 static if (LOG_LEASTAS)
794 {
795 import core.stdc.stdio : printf;
796 printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null");
797 printf("%s, %s\n", f.type.toChars(), g.type.toChars());
798 }
799
800 /* This works by calling g() with f()'s parameters, and
801 * if that is possible, then f() is at least as specialized
802 * as g() is.
803 */
804
805 TypeFunction tf = f.type.toTypeFunction();
806 TypeFunction tg = g.type.toTypeFunction();
807
808 /* If both functions have a 'this' pointer, and the mods are not
809 * the same and g's is not const, then this is less specialized.
810 */
811 if (f.needThis() && g.needThis() && tf.mod != tg.mod)
812 {
813 if (f.isCtorDeclaration())
814 {
815 if (!MODimplicitConv(tg.mod, tf.mod))
816 return MATCH.nomatch;
817 }
818 else
819 {
820 if (!MODimplicitConv(tf.mod, tg.mod))
821 return MATCH.nomatch;
822 }
823 }
824
825 /* Create a dummy array of arguments out of the parameters to f()
826 */
827 Expressions args;
828 foreach (u, p; tf.parameterList)
829 {
830 Expression e;
831 if (p.isReference())
832 {
833 e = new IdentifierExp(Loc.initial, p.ident);
834 e.type = p.type;
835 }
836 else
837 e = p.type.defaultInitLiteral(Loc.initial);
838 args.push(e);
839 }
840
841 MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
842 if (m > MATCH.nomatch)
843 {
844 /* A variadic parameter list is less specialized than a
845 * non-variadic one.
846 */
847 if (tf.parameterList.varargs && !tg.parameterList.varargs)
848 goto L1; // less specialized
849
850 static if (LOG_LEASTAS)
851 {
852 printf(" matches %d, so is least as specialized\n", m);
853 }
854 return m;
855 }
856 L1:
857 static if (LOG_LEASTAS)
858 {
859 printf(" doesn't match, so is not as specialized\n");
860 }
861 return MATCH.nomatch;
862 }
863
864 /********************************
865 * Searches for a label with the given identifier. This function will insert a new
866 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
867 *
868 * Params:
869 * ident = identifier of the requested label
870 * loc = location used when creating a new `LabelDsymbol`
871 *
872 * Returns: the `LabelDsymbol` for `ident`
873 */
874 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc)
875 {
876 Dsymbol s;
877 if (!labtab)
878 labtab = new DsymbolTable(); // guess we need one
879
880 s = labtab.lookup(ident);
881 if (!s)
882 {
883 s = new LabelDsymbol(ident, loc);
884 labtab.insert(s);
885 }
886 return cast(LabelDsymbol)s;
887 }
888
889 /*****************************************
890 * Determine lexical level difference from `this` to nested function `fd`.
891 * Params:
892 * fd = target of call
893 * intypeof = !=0 if inside typeof
894 * Returns:
895 * 0 same level
896 * >0 decrease nesting by number
897 * -1 increase nesting by 1 (`fd` is nested within `this`)
898 * LevelError error, `this` cannot call `fd`
899 */
900 extern (D) final int getLevel(FuncDeclaration fd, int intypeof)
901 {
902 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
903 Dsymbol fdparent = fd.toParent2();
904 if (fdparent == this)
905 return -1;
906
907 Dsymbol s = this;
908 int level = 0;
909 while (fd != s && fdparent != s.toParent2())
910 {
911 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
912 if (auto thisfd = s.isFuncDeclaration())
913 {
914 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
915 return LevelError;
916 }
917 else
918 {
919 if (auto thiscd = s.isAggregateDeclaration())
920 {
921 /* AggregateDeclaration::isNested returns true only when
922 * it has a hidden pointer.
923 * But, calling the function belongs unrelated lexical scope
924 * is still allowed inside typeof.
925 *
926 * struct Map(alias fun) {
927 * typeof({ return fun(); }) RetType;
928 * // No member function makes Map struct 'not nested'.
929 * }
930 */
931 if (!thiscd.isNested() && !intypeof)
932 return LevelError;
933 }
934 else
935 return LevelError;
936 }
937
938 s = s.toParentP(fd);
939 assert(s);
940 level++;
941 }
942 return level;
943 }
944
945 /***********************************
946 * Determine lexical level difference from `this` to nested function `fd`.
947 * Issue error if `this` cannot call `fd`.
948 *
949 * Params:
950 * loc = location for error messages
951 * sc = context
952 * fd = target of call
953 * decl = The `Declaration` that triggered this check.
954 * Used to provide a better error message only.
955 * Returns:
956 * 0 same level
957 * >0 decrease nesting by number
958 * -1 increase nesting by 1 (`fd` is nested within 'this')
959 * LevelError error
960 */
961 extern (D) final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
962 Declaration decl)
963 {
964 int level = getLevel(fd, sc.intypeof);
965 if (level != LevelError)
966 return level;
967
968 // Don't give error if in template constraint
969 if (!(sc.flags & SCOPE.constraint))
970 {
971 const(char)* xstatic = isStatic() ? "`static` " : "";
972 // better diagnostics for static functions
973 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
974 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
975 fd.toPrettyChars());
976 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
977 return LevelError;
978 }
979 return 1;
980 }
981
982 enum LevelError = -2;
983
984 override const(char)* toPrettyChars(bool QualifyTypes = false)
985 {
986 if (isMain())
987 return "D main";
988 else
989 return Dsymbol.toPrettyChars(QualifyTypes);
990 }
991
992 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
993 final const(char)* toFullSignature()
994 {
995 OutBuffer buf;
996 functionToBufferWithIdent(type.toTypeFunction(), buf, toChars(), isStatic);
997 return buf.extractChars();
998 }
999
1000 final bool isMain() const
1001 {
1002 return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested();
1003 }
1004
1005 final bool isCMain() const
1006 {
1007 return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1008 }
1009
1010 final bool isWinMain() const
1011 {
1012 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1013 version (none)
1014 {
1015 bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1016 printf("%s\n", x ? "yes" : "no");
1017 return x;
1018 }
1019 else
1020 {
1021 return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1022 }
1023 }
1024
1025 final bool isDllMain() const
1026 {
1027 return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember();
1028 }
1029
1030 final bool isRtInit() const
1031 {
1032 return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1033 }
1034
1035 override final bool isExport() const
1036 {
1037 return visibility.kind == Visibility.Kind.export_ || dllExport;
1038 }
1039
1040 override final bool isImportedSymbol() const
1041 {
1042 //printf("isImportedSymbol()\n");
1043 //printf("protection = %d\n", visibility);
1044 return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody;
1045 }
1046
1047 override final bool isCodeseg() const pure nothrow @nogc @safe
1048 {
1049 return true; // functions are always in the code segment
1050 }
1051
1052 override final bool isOverloadable() const
1053 {
1054 return true; // functions can be overloaded
1055 }
1056
1057 /***********************************
1058 * Override so it can work even if semantic() hasn't yet
1059 * been run.
1060 */
1061 override final bool isAbstract()
1062 {
1063 if (storage_class & STC.abstract_)
1064 return true;
1065 if (semanticRun >= PASS.semanticdone)
1066 return false;
1067
1068 if (_scope)
1069 {
1070 if (_scope.stc & STC.abstract_)
1071 return true;
1072 parent = _scope.parent;
1073 Dsymbol parent = toParent();
1074 if (parent.isInterfaceDeclaration())
1075 return true;
1076 }
1077 return false;
1078 }
1079
1080 /**********************************
1081 * Decide if attributes for this function can be inferred from examining
1082 * the function body.
1083 * Returns:
1084 * true if can
1085 */
1086 final bool canInferAttributes(Scope* sc)
1087 {
1088 if (!fbody)
1089 return false;
1090
1091 if (isVirtualMethod() &&
1092 /*
1093 * https://issues.dlang.org/show_bug.cgi?id=21719
1094 *
1095 * If we have an auto virtual function we can infer
1096 * the attributes.
1097 */
1098 !(inferRetType && !isCtorDeclaration()))
1099 return false; // since they may be overridden
1100
1101 if (sc.func &&
1102 /********** this is for backwards compatibility for the moment ********/
1103 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1104 return true;
1105
1106 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1107 (storage_class & STC.inference) || // do attribute inference
1108 (inferRetType && !isCtorDeclaration()))
1109 return true;
1110
1111 if (isInstantiated())
1112 {
1113 auto ti = parent.isTemplateInstance();
1114 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1115 return true;
1116 }
1117
1118 return false;
1119 }
1120
1121 /*****************************************
1122 * Initialize for inferring the attributes of this function.
1123 */
1124 final void initInferAttributes()
1125 {
1126 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1127 TypeFunction tf = type.toTypeFunction();
1128 if (tf.purity == PURE.impure) // purity not specified
1129 purityInprocess = true;
1130
1131 if (tf.trust == TRUST.default_)
1132 safetyInprocess = true;
1133
1134 if (!tf.isnothrow)
1135 nothrowInprocess = true;
1136
1137 if (!tf.isnogc)
1138 nogcInprocess = true;
1139
1140 if (!isVirtual() || this.isIntroducing())
1141 returnInprocess = true;
1142
1143 // Initialize for inferring STC.scope_
1144 inferScope = true;
1145 }
1146
1147 final PURE isPure()
1148 {
1149 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1150
1151
1152 TypeFunction tf = type.toTypeFunction();
1153 if (purityInprocess)
1154 setImpure();
1155 if (tf.purity == PURE.fwdref)
1156 tf.purityLevel();
1157 PURE purity = tf.purity;
1158 if (purity > PURE.weak && isNested())
1159 purity = PURE.weak;
1160 if (purity > PURE.weak && needThis())
1161 {
1162 // The attribute of the 'this' reference affects purity strength
1163 if (type.mod & MODFlags.immutable_)
1164 {
1165 }
1166 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1167 purity = PURE.const_;
1168 else
1169 purity = PURE.weak;
1170 }
1171 tf.purity = purity;
1172 // ^ This rely on the current situation that every FuncDeclaration has a
1173 // unique TypeFunction.
1174 return purity;
1175 }
1176
1177 extern (D) final PURE isPureBypassingInference()
1178 {
1179 if (purityInprocess)
1180 return PURE.fwdref;
1181 else
1182 return isPure();
1183 }
1184
1185 /**************************************
1186 * The function is doing something impure, so mark it as impure.
1187 *
1188 * Params:
1189 * loc = location of impure action
1190 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1191 * arg0 = (optional) argument to format string
1192 *
1193 * Returns: `true` if there's a purity error
1194 */
1195 extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
1196 {
1197 if (purityInprocess)
1198 {
1199 purityInprocess = false;
1200 if (fmt)
1201 pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
1202 else if (arg0)
1203 pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
1204
1205 if (fes)
1206 fes.func.setImpure(loc, fmt, arg0);
1207 }
1208 else if (isPure())
1209 return true;
1210 return false;
1211 }
1212
1213 extern (D) final uint flags()
1214 {
1215 return bitFields;
1216 }
1217
1218 extern (D) final uint flags(uint f)
1219 {
1220 bitFields = f;
1221 return bitFields;
1222 }
1223
1224 final bool isSafe()
1225 {
1226 if (safetyInprocess)
1227 setUnsafe();
1228 return type.toTypeFunction().trust == TRUST.safe;
1229 }
1230
1231 extern (D) final bool isSafeBypassingInference()
1232 {
1233 return !(safetyInprocess) && isSafe();
1234 }
1235
1236 final bool isTrusted()
1237 {
1238 if (safetyInprocess)
1239 setUnsafe();
1240 return type.toTypeFunction().trust == TRUST.trusted;
1241 }
1242
1243 /**************************************
1244 * The function is doing something unsafe, so mark it as unsafe.
1245 *
1246 * Params:
1247 * gag = surpress error message (used in escape.d)
1248 * loc = location of error
1249 * fmt = printf-style format string
1250 * arg0 = (optional) argument for first %s format specifier
1251 * arg1 = (optional) argument for second %s format specifier
1252 * arg2 = (optional) argument for third %s format specifier
1253 * Returns: whether there's a safe error
1254 */
1255 extern (D) final bool setUnsafe(
1256 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
1257 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
1258 {
1259 if (safetyInprocess)
1260 {
1261 safetyInprocess = false;
1262 type.toTypeFunction().trust = TRUST.system;
1263 if (fmt || arg0)
1264 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
1265
1266 if (fes)
1267 fes.func.setUnsafe();
1268 }
1269 else if (isSafe())
1270 {
1271 if (!gag && fmt)
1272 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
1273
1274 return true;
1275 }
1276 return false;
1277 }
1278
1279 /**************************************
1280 * The function is calling `@system` function `f`, so mark it as unsafe.
1281 *
1282 * Params:
1283 * f = function being called (needed for diagnostic of inferred functions)
1284 * Returns: whether there's a safe error
1285 */
1286 extern (D) final bool setUnsafeCall(FuncDeclaration f)
1287 {
1288 return setUnsafe(false, f.loc, null, f, null);
1289 }
1290
1291 final bool isNogc()
1292 {
1293 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1294 if (nogcInprocess)
1295 setGC(loc, null);
1296 return type.toTypeFunction().isnogc;
1297 }
1298
1299 extern (D) final bool isNogcBypassingInference()
1300 {
1301 return !nogcInprocess && isNogc();
1302 }
1303
1304 /**************************************
1305 * The function is doing something that may allocate with the GC,
1306 * so mark it as not nogc (not no-how).
1307 *
1308 * Params:
1309 * loc = location of impure action
1310 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1311 * arg0 = (optional) argument to format string
1312 *
1313 * Returns:
1314 * true if function is marked as @nogc, meaning a user error occurred
1315 */
1316 extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
1317 {
1318 //printf("setGC() %s\n", toChars());
1319 if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1320 {
1321 this.semantic2(_scope);
1322 this.semantic3(_scope);
1323 }
1324
1325 if (nogcInprocess)
1326 {
1327 nogcInprocess = false;
1328 if (fmt)
1329 nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
1330 else if (arg0)
1331 nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
1332
1333 type.toTypeFunction().isnogc = false;
1334 if (fes)
1335 fes.func.setGC(Loc.init, null, null);
1336 }
1337 else if (isNogc())
1338 return true;
1339 return false;
1340 }
1341
1342 /**************************************
1343 * The function calls non-`@nogc` function f, mark it as not nogc.
1344 * Params:
1345 * f = function being called
1346 * Returns:
1347 * true if function is marked as @nogc, meaning a user error occurred
1348 */
1349 extern (D) final bool setGCCall(FuncDeclaration f)
1350 {
1351 return setGC(loc, null, f);
1352 }
1353
1354 /**************************************
1355 * The function is doing something that may throw an exception, register that in case nothrow is being inferred
1356 *
1357 * Params:
1358 * loc = location of action
1359 * fmt = format string for error message
1360 * arg0 = (optional) argument to format string
1361 */
1362 extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
1363 {
1364 if (nothrowInprocess && !nothrowViolation)
1365 {
1366 nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
1367 }
1368 }
1369
1370 /**************************************
1371 * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
1372 * Params:
1373 * loc = location of call
1374 * f = function being called
1375 */
1376 extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
1377 {
1378 return setThrow(loc, null, f);
1379 }
1380
1381 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1382 {
1383 if (!global.params.v.gc)
1384 return;
1385
1386 Module m = getModule();
1387 if (m && m.isRoot() && !inUnittest())
1388 {
1389 message(loc, "vgc: %s", warn);
1390 }
1391 }
1392
1393 /********************************************
1394 * See if pointers from function parameters, mutable globals, or uplevel functions
1395 * could leak into return value.
1396 * Returns:
1397 * true if the function return value is isolated from
1398 * any inputs to the function
1399 */
1400 extern (D) final bool isReturnIsolated()
1401 {
1402 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1403 TypeFunction tf = type.toTypeFunction();
1404 assert(tf.next);
1405
1406 Type treti = tf.next;
1407 if (tf.isref)
1408 return isTypeIsolatedIndirect(treti); // check influence from parameters
1409
1410 return isTypeIsolated(treti);
1411 }
1412
1413 /********************
1414 * See if pointers from function parameters, mutable globals, or uplevel functions
1415 * could leak into type `t`.
1416 * Params:
1417 * t = type to check if it is isolated
1418 * Returns:
1419 * true if `t` is isolated from
1420 * any inputs to the function
1421 */
1422 extern (D) final bool isTypeIsolated(Type t)
1423 {
1424 StringTable!Type parentTypes;
1425 const uniqueTypeID = t.getUniqueID();
1426 if (uniqueTypeID)
1427 {
1428 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1429 if (cacheResultPtr !is null)
1430 return *cacheResultPtr;
1431
1432 parentTypes._init();
1433 const isIsolated = isTypeIsolated(t, parentTypes);
1434 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1435 return isIsolated;
1436 }
1437 else
1438 {
1439 parentTypes._init();
1440 return isTypeIsolated(t, parentTypes);
1441 }
1442 }
1443
1444 ///ditto
1445 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1446 {
1447 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1448
1449 t = t.baseElemOf();
1450 switch (t.ty)
1451 {
1452 case Tarray:
1453 case Tpointer:
1454 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1455
1456 case Taarray:
1457 case Tclass:
1458 return isTypeIsolatedIndirect(t);
1459
1460 case Tstruct:
1461 /* Drill down and check the struct's fields
1462 */
1463 auto sym = t.toDsymbol(null).isStructDeclaration();
1464 const tName = t.toChars.toDString;
1465 const entry = parentTypes.insert(tName, t);
1466 if (entry == null)
1467 {
1468 //we've already seen this type in a parent, not isolated
1469 return false;
1470 }
1471 foreach (v; sym.fields)
1472 {
1473 Type tmi = v.type.addMod(t.mod);
1474 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1475 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1476 if (!isTypeIsolated(tmi, parentTypes))
1477 return false;
1478 }
1479 return true;
1480
1481 default:
1482 return true;
1483 }
1484 }
1485
1486 /********************************************
1487 * Params:
1488 * t = type of object to test one level of indirection down
1489 * Returns:
1490 * true if an object typed `t` has no indirections
1491 * which could have come from the function's parameters, mutable
1492 * globals, or uplevel functions.
1493 */
1494 private bool isTypeIsolatedIndirect(Type t)
1495 {
1496 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1497 assert(t);
1498
1499 /* Since `t` is one level down from an indirection, it could pick
1500 * up a reference to a mutable global or an outer function, so
1501 * return false.
1502 */
1503 if (!isPureBypassingInference() || isNested())
1504 return false;
1505
1506 TypeFunction tf = type.toTypeFunction();
1507
1508 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1509
1510 foreach (i, fparam; tf.parameterList)
1511 {
1512 Type tp = fparam.type;
1513 if (!tp)
1514 continue;
1515
1516 if (fparam.isLazy() || fparam.isReference())
1517 {
1518 if (!traverseIndirections(tp, t))
1519 return false;
1520 continue;
1521 }
1522
1523 /* Goes down one level of indirection, then calls traverseIndirection() on
1524 * the result.
1525 * Returns:
1526 * true if t is isolated from tp
1527 */
1528 static bool traverse(Type tp, Type t)
1529 {
1530 tp = tp.baseElemOf();
1531 switch (tp.ty)
1532 {
1533 case Tarray:
1534 case Tpointer:
1535 return traverseIndirections(tp.nextOf(), t);
1536
1537 case Taarray:
1538 case Tclass:
1539 return traverseIndirections(tp, t);
1540
1541 case Tstruct:
1542 /* Drill down and check the struct's fields
1543 */
1544 auto sym = tp.toDsymbol(null).isStructDeclaration();
1545 foreach (v; sym.fields)
1546 {
1547 Type tprmi = v.type.addMod(tp.mod);
1548 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1549 if (!traverse(tprmi, t))
1550 return false;
1551 }
1552 return true;
1553
1554 default:
1555 return true;
1556 }
1557 }
1558
1559 if (!traverse(tp, t))
1560 return false;
1561 }
1562 // The 'this' reference is a parameter, too
1563 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1564 {
1565 Type tthis = ad.getType().addMod(tf.mod);
1566 //printf("\ttthis = %s\n", tthis.toChars());
1567 if (!traverseIndirections(tthis, t))
1568 return false;
1569 }
1570
1571 return true;
1572 }
1573
1574 /****************************************
1575 * Determine if function needs a static frame pointer.
1576 * Returns:
1577 * `true` if function is really nested within other function.
1578 * Contracts:
1579 * If isNested() returns true, isThis() should return false,
1580 * unless the function needs a dual-context pointer.
1581 */
1582 bool isNested() const
1583 {
1584 auto f = toAliasFunc();
1585 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1586 return ((f.storage_class & STC.static_) == 0) &&
1587 (f._linkage == LINK.d) &&
1588 (f.toParent2().isFuncDeclaration() !is null ||
1589 f.toParent2() !is f.toParentLocal());
1590 }
1591
1592 /****************************************
1593 * Determine if function is a non-static member function
1594 * that has an implicit 'this' expression.
1595 * Returns:
1596 * The aggregate it is a member of, or null.
1597 * Contracts:
1598 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1599 * otherwise if isThis() returns true, isNested() should return false.
1600 */
1601 override inout(AggregateDeclaration) isThis() inout
1602 {
1603 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1604 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1605 //printf("-FuncDeclaration::isThis() %p\n", ad);
1606 return ad;
1607 }
1608
1609 override final bool needThis()
1610 {
1611 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1612 return toAliasFunc().isThis() !is null;
1613 }
1614
1615 // Determine if a function is pedantically virtual
1616 final bool isVirtualMethod()
1617 {
1618 if (toAliasFunc() != this)
1619 return toAliasFunc().isVirtualMethod();
1620
1621 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1622 if (!isVirtual())
1623 return false;
1624 // If it's a final method, and does not override anything, then it is not virtual
1625 if (isFinalFunc() && foverrides.length == 0)
1626 {
1627 return false;
1628 }
1629 return true;
1630 }
1631
1632 // Determine if function goes into virtual function pointer table
1633 bool isVirtual() const
1634 {
1635 if (toAliasFunc() != this)
1636 return toAliasFunc().isVirtual();
1637
1638 auto p = toParent();
1639
1640 if (!isMember || !p.isClassDeclaration)
1641 return false;
1642
1643 if (p.isClassDeclaration.classKind == ClassKind.objc)
1644 return .objc.isVirtual(this);
1645
1646 version (none)
1647 {
1648 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1649 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1650 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1651 }
1652 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1653 }
1654
1655 final bool isFinalFunc() const
1656 {
1657 if (toAliasFunc() != this)
1658 return toAliasFunc().isFinalFunc();
1659
1660 version (none)
1661 {{
1662 auto cd = toParent().isClassDeclaration();
1663 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1664 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1665 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1666 if (cd)
1667 printf("\tmember of %s\n", cd.toChars());
1668 }}
1669 if (!isMember())
1670 return false;
1671 if (Declaration.isFinal())
1672 return true;
1673 auto cd = toParent().isClassDeclaration();
1674 return (cd !is null) && (cd.storage_class & STC.final_);
1675 }
1676
1677 bool addPreInvariant()
1678 {
1679 auto ad = isThis();
1680 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1681 return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
1682 }
1683
1684 bool addPostInvariant()
1685 {
1686 auto ad = isThis();
1687 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1688 return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
1689 }
1690
1691 override const(char)* kind() const
1692 {
1693 return this.isGenerated() ? "generated function" : "function";
1694 }
1695
1696 /********************************************
1697 * Returns:
1698 * true if there are no overloads of this function
1699 */
1700 final bool isUnique() const
1701 {
1702 bool result = false;
1703 overloadApply(cast() this, (Dsymbol s)
1704 {
1705 auto f = s.isFuncDeclaration();
1706 auto td = s.isTemplateDeclaration();
1707 if (!f && !td)
1708 return 0;
1709 if (result)
1710 {
1711 result = false;
1712 return 1; // ambiguous, done
1713 }
1714 else
1715 {
1716 result = true;
1717 return 0;
1718 }
1719 });
1720 return result;
1721 }
1722
1723 /*********************************************
1724 * In the current function, we are calling 'this' function.
1725 * 1. Check to see if the current function can call 'this' function, issue error if not.
1726 * 2. If the current function is not the parent of 'this' function, then add
1727 * the current function to the list of siblings of 'this' function.
1728 * 3. If the current function is a literal, and it's accessing an uplevel scope,
1729 * then mark it as a delegate.
1730 * Returns true if error occurs.
1731 */
1732 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
1733 {
1734 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1735
1736 if (auto fld = this.isFuncLiteralDeclaration())
1737 {
1738 if (fld.tok == TOK.reserved)
1739 {
1740 fld.tok = TOK.function_;
1741 fld.vthis = null;
1742 }
1743 }
1744
1745 if (!parent || parent == sc.parent)
1746 return false;
1747 if (ident == Id.require || ident == Id.ensure)
1748 return false;
1749 if (!isThis() && !isNested())
1750 return false;
1751
1752 // The current function
1753 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
1754 if (!fdthis)
1755 return false; // out of function scope
1756
1757 Dsymbol p = toParentLocal();
1758 Dsymbol p2 = toParent2();
1759
1760 // Function literals from fdthis to p must be delegates
1761 ensureStaticLinkTo(fdthis, p);
1762 if (p != p2)
1763 ensureStaticLinkTo(fdthis, p2);
1764
1765 if (isNested())
1766 {
1767 // The function that this function is in
1768 bool checkEnclosing(FuncDeclaration fdv)
1769 {
1770 if (!fdv)
1771 return false;
1772 if (fdv == fdthis)
1773 return false;
1774
1775 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1776 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1777 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1778
1779 // Add this function to the list of those which called us
1780 if (fdthis != this)
1781 {
1782 bool found = false;
1783 for (size_t i = 0; i < siblingCallers.length; ++i)
1784 {
1785 if (siblingCallers[i] == fdthis)
1786 found = true;
1787 }
1788 if (!found)
1789 {
1790 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
1791 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
1792 {
1793 siblingCallers.push(fdthis);
1794 computedEscapingSiblings = false;
1795 }
1796 }
1797 }
1798
1799 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
1800 if (lv == LevelError)
1801 return true; // error
1802 if (lv == -1)
1803 return false; // downlevel call
1804 if (lv == 0)
1805 return false; // same level call
1806
1807 return false; // Uplevel call
1808 }
1809
1810 if (checkEnclosing(p.isFuncDeclaration()))
1811 return true;
1812 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
1813 return true;
1814 }
1815 return false;
1816 }
1817
1818 /*******************************
1819 * Look at all the variables in this function that are referenced
1820 * by nested functions, and determine if a closure needs to be
1821 * created for them.
1822 */
1823 final bool needsClosure()
1824 {
1825 /* Need a closure for all the closureVars[] if any of the
1826 * closureVars[] are accessed by a
1827 * function that escapes the scope of this function.
1828 * We take the conservative approach and decide that a function needs
1829 * a closure if it:
1830 * 1) is a virtual function
1831 * 2) has its address taken
1832 * 3) has a parent that escapes
1833 * 4) calls another nested function that needs a closure
1834 *
1835 * Note that since a non-virtual function can be called by
1836 * a virtual one, if that non-virtual function accesses a closure
1837 * var, the closure still has to be taken. Hence, we check for isThis()
1838 * instead of isVirtual(). (thanks to David Friedman)
1839 *
1840 * When the function returns a local struct or class, `requiresClosure`
1841 * is already set to `true` upon entering this function when the
1842 * struct/class refers to a local variable and a closure is needed.
1843 */
1844 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
1845
1846 if (requiresClosure)
1847 goto Lyes;
1848
1849 for (size_t i = 0; i < closureVars.length; i++)
1850 {
1851 VarDeclaration v = closureVars[i];
1852 //printf("\tv = %s\n", v.toChars());
1853
1854 for (size_t j = 0; j < v.nestedrefs.length; j++)
1855 {
1856 FuncDeclaration f = v.nestedrefs[j];
1857 assert(f != this);
1858
1859 /* __require and __ensure will always get called directly,
1860 * so they never make outer functions closure.
1861 */
1862 if (f.ident == Id.require || f.ident == Id.ensure)
1863 continue;
1864
1865 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
1866
1867 /* Look to see if f escapes. We consider all parents of f within
1868 * this, and also all siblings which call f; if any of them escape,
1869 * so does f.
1870 * Mark all affected functions as requiring closures.
1871 */
1872 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
1873 {
1874 FuncDeclaration fx = s.isFuncDeclaration();
1875 if (!fx)
1876 continue;
1877 if (fx.isThis() || fx.tookAddressOf)
1878 {
1879 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
1880
1881 /* Mark as needing closure any functions between this and f
1882 */
1883 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
1884
1885 requiresClosure = true;
1886 }
1887
1888 /* We also need to check if any sibling functions that
1889 * called us, have escaped. This is recursive: we need
1890 * to check the callers of our siblings.
1891 */
1892 if (checkEscapingSiblings(fx, this))
1893 requiresClosure = true;
1894
1895 /* https://issues.dlang.org/show_bug.cgi?id=12406
1896 * Iterate all closureVars to mark all descendant
1897 * nested functions that access to the closing context of this function.
1898 */
1899 }
1900 }
1901 }
1902 if (requiresClosure)
1903 goto Lyes;
1904
1905 return false;
1906
1907 Lyes:
1908 return true;
1909 }
1910
1911 /***********************************************
1912 * Check that the function contains any closure.
1913 * If it's @nogc, report suitable errors.
1914 * This is mostly consistent with FuncDeclaration::needsClosure().
1915 *
1916 * Returns:
1917 * true if any errors occur.
1918 */
1919 extern (C++) final bool checkClosure()
1920 {
1921 //printf("checkClosure() %s\n", toPrettyChars());
1922 if (!needsClosure())
1923 return false;
1924
1925 if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
1926 {
1927 .error(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
1928 if (global.gag) // need not report supplemental errors
1929 return true;
1930 }
1931 else if (!global.params.useGC)
1932 {
1933 .error(loc, "%s `%s` is `-betterC` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
1934 if (global.gag) // need not report supplemental errors
1935 return true;
1936 }
1937 else
1938 {
1939 printGCUsage(loc, "using closure causes GC allocation");
1940 return false;
1941 }
1942
1943 FuncDeclarations a;
1944 foreach (v; closureVars)
1945 {
1946 foreach (f; v.nestedrefs)
1947 {
1948 assert(f !is this);
1949
1950 LcheckAncestorsOfANestedRef:
1951 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
1952 {
1953 auto fx = s.isFuncDeclaration();
1954 if (!fx)
1955 continue;
1956 if (fx.isThis() ||
1957 fx.tookAddressOf ||
1958 checkEscapingSiblings(fx, this))
1959 {
1960 foreach (f2; a)
1961 {
1962 if (f2 == f)
1963 break LcheckAncestorsOfANestedRef;
1964 }
1965 a.push(f);
1966 .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`",
1967 f.kind, f.toPrettyChars(), v.toChars());
1968 if (v.ident != Id.This)
1969 .errorSupplemental(v.loc, "`%s` declared here", v.toChars());
1970
1971 break LcheckAncestorsOfANestedRef;
1972 }
1973 }
1974 }
1975 }
1976
1977 return true;
1978 }
1979
1980 /***********************************************
1981 * Determine if function's variables are referenced by a function
1982 * nested within it.
1983 */
1984 final bool hasNestedFrameRefs()
1985 {
1986 if (closureVars.length)
1987 return true;
1988
1989 /* If a virtual function has contracts, assume its variables are referenced
1990 * by those contracts, even if they aren't. Because they might be referenced
1991 * by the overridden or overriding function's contracts.
1992 * This can happen because frequire and fensure are implemented as nested functions,
1993 * and they can be called directly by an overriding function and the overriding function's
1994 * context had better match, or
1995 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
1996 */
1997 if (fdrequire || fdensure)
1998 return true;
1999
2000 if (foverrides.length && isVirtualMethod())
2001 {
2002 for (size_t i = 0; i < foverrides.length; i++)
2003 {
2004 FuncDeclaration fdv = foverrides[i];
2005 if (fdv.hasNestedFrameRefs())
2006 return true;
2007 }
2008 }
2009 return false;
2010 }
2011
2012 /****************************************************
2013 * Check whether result variable can be built.
2014 * Returns:
2015 * `true` if the function has a return type that
2016 * is different from `void`.
2017 */
2018 extern (D) private bool canBuildResultVar()
2019 {
2020 auto f = cast(TypeFunction)type;
2021 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2022 }
2023
2024 /****************************************************
2025 * Declare result variable lazily.
2026 */
2027 extern (D) final void buildResultVar(Scope* sc, Type tret)
2028 {
2029 if (!vresult)
2030 {
2031 Loc loc = fensure ? fensure.loc : this.loc;
2032
2033 /* If inferRetType is true, tret may not be a correct return type yet.
2034 * So, in here it may be a temporary type for vresult, and after
2035 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2036 */
2037 vresult = new VarDeclaration(loc, tret, Id.result, null);
2038 vresult.storage_class |= STC.nodtor | STC.temp;
2039 if (!isVirtual())
2040 vresult.storage_class |= STC.const_;
2041 vresult.storage_class |= STC.result;
2042
2043 // set before the semantic() for checkNestedReference()
2044 vresult.parent = this;
2045 }
2046
2047 if (sc && vresult.semanticRun == PASS.initial)
2048 {
2049 TypeFunction tf = type.toTypeFunction();
2050 if (tf.isref)
2051 vresult.storage_class |= STC.ref_;
2052 vresult.type = tret;
2053
2054 vresult.dsymbolSemantic(sc);
2055
2056 if (!sc.insert(vresult))
2057 .error(loc, "%s `%s` out result %s is already defined", kind, toPrettyChars, vresult.toChars());
2058 assert(vresult.parent == this);
2059 }
2060 }
2061
2062 /****************************************************
2063 * Merge into this function the 'in' contracts of all it overrides.
2064 * 'in's are OR'd together, i.e. only one of them needs to pass.
2065 */
2066 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2067 {
2068 /* If a base function and its override both have an IN contract, then
2069 * only one of them needs to succeed. This is done by generating:
2070 *
2071 * void derived.in() {
2072 * try {
2073 * base.in();
2074 * }
2075 * catch () {
2076 * ... body of derived.in() ...
2077 * }
2078 * }
2079 *
2080 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2081 * If base.in() throws, then derived.in()'s body is executed.
2082 */
2083
2084 foreach (fdv; foverrides)
2085 {
2086 /* The semantic pass on the contracts of the overridden functions must
2087 * be completed before code generation occurs.
2088 * https://issues.dlang.org/show_bug.cgi?id=3602
2089 */
2090 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2091 {
2092 assert(fdv._scope);
2093 Scope* sc = fdv._scope.push();
2094 sc.stc &= ~STC.override_;
2095 fdv.semantic3(sc);
2096 sc.pop();
2097 }
2098
2099 sf = fdv.mergeFrequire(sf, params);
2100 if (!sf || !fdv.fdrequire)
2101 return null;
2102 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2103 /* Make the call:
2104 * try { __require(params); }
2105 * catch (Throwable) { frequire; }
2106 */
2107 params = Expression.arraySyntaxCopy(params);
2108 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2109 Statement s2 = new ExpStatement(loc, e);
2110
2111 auto c = new Catch(loc, getThrowable(), null, sf);
2112 c.internalCatch = true;
2113 auto catches = new Catches();
2114 catches.push(c);
2115 sf = new TryCatchStatement(loc, s2, catches);
2116 }
2117 return sf;
2118 }
2119
2120 /****************************************************
2121 * Merge into this function the 'in' contracts of all it overrides.
2122 */
2123 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2124 {
2125 /* If a base function and its override both have an IN contract, then
2126 * the override in contract must widen the guarantee of the base contract.
2127 * This is checked by generating:
2128 *
2129 * void derived.in() {
2130 * try {
2131 * ... body of derived.in() ...
2132 * }
2133 * catch () {
2134 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2135 * base.in();
2136 * assert(false, "Logic error: " ~ thr.msg);
2137 * }
2138 * }
2139 */
2140
2141 foreach (fdv; foverrides)
2142 {
2143 /* The semantic pass on the contracts of the overridden functions must
2144 * be completed before code generation occurs.
2145 * https://issues.dlang.org/show_bug.cgi?id=3602
2146 */
2147 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2148 {
2149 assert(fdv._scope);
2150 Scope* sc = fdv._scope.push();
2151 sc.stc &= ~STC.override_;
2152 fdv.semantic3(sc);
2153 sc.pop();
2154 }
2155
2156 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2157 if (sf && fdv.fdrequire)
2158 {
2159 const loc = this.fdrequire.loc;
2160
2161 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2162 /* Make the call:
2163 * try { frequire; }
2164 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2165 */
2166 Identifier id = Identifier.generateId("thr");
2167 params = Expression.arraySyntaxCopy(params);
2168 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2169 Statement s2 = new ExpStatement(loc, e);
2170 // assert(false, ...)
2171 // TODO make this a runtime helper to allow:
2172 // - chaining the original expression
2173 // - nogc concatenation
2174 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2175 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2176
2177 Statement s3 = new CompoundStatement(loc, s2, fail);
2178
2179 auto c = new Catch(loc, getThrowable(), id, s3);
2180 c.internalCatch = true;
2181 auto catches = new Catches();
2182 catches.push(c);
2183 sf = new TryCatchStatement(loc, sf, catches);
2184 }
2185 else
2186 return null;
2187 }
2188 return sf;
2189 }
2190
2191 /****************************************************
2192 * Determine whether an 'out' contract is declared inside
2193 * the given function or any of its overrides.
2194 * Params:
2195 * fd = the function to search
2196 * Returns:
2197 * true found an 'out' contract
2198 */
2199 static bool needsFensure(FuncDeclaration fd) @safe
2200 {
2201 if (fd.fensures)
2202 return true;
2203
2204 foreach (fdv; fd.foverrides)
2205 {
2206 if (needsFensure(fdv))
2207 return true;
2208 }
2209 return false;
2210 }
2211
2212 /****************************************************
2213 * Rewrite contracts as statements.
2214 */
2215 final void buildEnsureRequire()
2216 {
2217
2218 if (frequires)
2219 {
2220 /* in { statements1... }
2221 * in { statements2... }
2222 * ...
2223 * becomes:
2224 * in { { statements1... } { statements2... } ... }
2225 */
2226 assert(frequires.length);
2227 auto loc = (*frequires)[0].loc;
2228 auto s = new Statements;
2229 foreach (r; *frequires)
2230 {
2231 s.push(new ScopeStatement(r.loc, r, r.loc));
2232 }
2233 frequire = new CompoundStatement(loc, s);
2234 }
2235
2236 if (fensures)
2237 {
2238 /* out(id1) { statements1... }
2239 * out(id2) { statements2... }
2240 * ...
2241 * becomes:
2242 * out(__result) { { ref id1 = __result; { statements1... } }
2243 * { ref id2 = __result; { statements2... } } ... }
2244 */
2245 assert(fensures.length);
2246 auto loc = (*fensures)[0].ensure.loc;
2247 auto s = new Statements;
2248 foreach (r; *fensures)
2249 {
2250 if (r.id && canBuildResultVar())
2251 {
2252 auto rloc = r.ensure.loc;
2253 auto resultId = new IdentifierExp(rloc, Id.result);
2254 auto init = new ExpInitializer(rloc, resultId);
2255 auto stc = STC.ref_ | STC.temp | STC.result;
2256 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2257 auto sdecl = new ExpStatement(rloc, decl);
2258 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2259 }
2260 else
2261 {
2262 s.push(r.ensure);
2263 }
2264 }
2265 fensure = new CompoundStatement(loc, s);
2266 }
2267
2268 if (!isVirtual())
2269 return;
2270
2271 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2272 * functions means that overriding functions can call them.
2273 */
2274 TypeFunction f = cast(TypeFunction) type;
2275
2276 /* Make a copy of the parameters and make them all ref */
2277 static Parameters* toRefCopy(ParameterList parameterList)
2278 {
2279 auto result = new Parameters();
2280
2281 foreach (n, p; parameterList)
2282 {
2283 p = p.syntaxCopy();
2284 if (!p.isLazy())
2285 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2286 p.defaultArg = null; // won't be the same with ref
2287 result.push(p);
2288 }
2289
2290 return result;
2291 }
2292
2293 if (frequire)
2294 {
2295 /* in { ... }
2296 * becomes:
2297 * void __require(ref params) { ... }
2298 * __require(params);
2299 */
2300 Loc loc = frequire.loc;
2301 fdrequireParams = new Expressions();
2302 if (parameters)
2303 {
2304 foreach (vd; *parameters)
2305 fdrequireParams.push(new VarExp(loc, vd));
2306 }
2307 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2308 auto fparams = toRefCopy(fo.parameterList);
2309 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2310 tf.isnothrow = f.isnothrow;
2311 tf.isnogc = f.isnogc;
2312 tf.purity = f.purity;
2313 tf.trust = f.trust;
2314 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2315 fd.fbody = frequire;
2316 Statement s1 = new ExpStatement(loc, fd);
2317 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2318 Statement s2 = new ExpStatement(loc, e);
2319 frequire = new CompoundStatement(loc, s1, s2);
2320 fdrequire = fd;
2321 }
2322
2323 /* We need to set fdensureParams here and not in the block below to
2324 * have the parameters available when calling a base class ensure(),
2325 * even if this function doesn't have an out contract.
2326 */
2327 fdensureParams = new Expressions();
2328 if (canBuildResultVar())
2329 fdensureParams.push(new IdentifierExp(loc, Id.result));
2330 if (parameters)
2331 {
2332 foreach (vd; *parameters)
2333 fdensureParams.push(new VarExp(loc, vd));
2334 }
2335
2336 if (fensure)
2337 {
2338 /* out (result) { ... }
2339 * becomes:
2340 * void __ensure(ref tret result, ref params) { ... }
2341 * __ensure(result, params);
2342 */
2343 Loc loc = fensure.loc;
2344 auto fparams = new Parameters();
2345 if (canBuildResultVar())
2346 {
2347 Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2348 fparams.push(p);
2349 }
2350 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2351 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2352 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2353 tf.isnothrow = f.isnothrow;
2354 tf.isnogc = f.isnogc;
2355 tf.purity = f.purity;
2356 tf.trust = f.trust;
2357 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2358 fd.fbody = fensure;
2359 Statement s1 = new ExpStatement(loc, fd);
2360 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2361 Statement s2 = new ExpStatement(loc, e);
2362 fensure = new CompoundStatement(loc, s1, s2);
2363 fdensure = fd;
2364 }
2365 }
2366
2367 /****************************************************
2368 * Merge into this function the 'out' contracts of all it overrides.
2369 * 'out's are AND'd together, i.e. all of them need to pass.
2370 */
2371 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2372 {
2373 /* Same comments as for mergeFrequire(), except that we take care
2374 * of generating a consistent reference to the 'result' local by
2375 * explicitly passing 'result' to the nested function as a reference
2376 * argument.
2377 * This won't work for the 'this' parameter as it would require changing
2378 * the semantic code for the nested function so that it looks on the parameter
2379 * list for the 'this' pointer, something that would need an unknown amount
2380 * of tweaking of various parts of the compiler that I'd rather leave alone.
2381 */
2382 foreach (fdv; foverrides)
2383 {
2384 /* The semantic pass on the contracts of the overridden functions must
2385 * be completed before code generation occurs.
2386 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2387 * https://issues.dlang.org/show_bug.cgi?id=5230
2388 */
2389 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2390 {
2391 assert(fdv._scope);
2392 Scope* sc = fdv._scope.push();
2393 sc.stc &= ~STC.override_;
2394 fdv.semantic3(sc);
2395 sc.pop();
2396 }
2397
2398 sf = fdv.mergeFensure(sf, oid, params);
2399 if (fdv.fdensure)
2400 {
2401 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2402 // Make the call: __ensure(result, params)
2403 params = Expression.arraySyntaxCopy(params);
2404 if (canBuildResultVar())
2405 {
2406 Type t1 = fdv.type.nextOf().toBasetype();
2407 Type t2 = this.type.nextOf().toBasetype();
2408 if (t1.isBaseOf(t2, null))
2409 {
2410 /* Making temporary reference variable is necessary
2411 * in covariant return.
2412 * https://issues.dlang.org/show_bug.cgi?id=5204
2413 * https://issues.dlang.org/show_bug.cgi?id=10479
2414 */
2415 Expression* eresult = &(*params)[0];
2416 auto ei = new ExpInitializer(Loc.initial, *eresult);
2417 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2418 v.storage_class |= STC.temp;
2419 auto de = new DeclarationExp(Loc.initial, v);
2420 auto ve = new VarExp(Loc.initial, v);
2421 *eresult = new CommaExp(Loc.initial, de, ve);
2422 }
2423 }
2424 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2425 Statement s2 = new ExpStatement(loc, e);
2426
2427 if (sf)
2428 {
2429 sf = new CompoundStatement(sf.loc, s2, sf);
2430 }
2431 else
2432 sf = s2;
2433 }
2434 }
2435 return sf;
2436 }
2437
2438 /*********************************************
2439 * Returns: the function's parameter list, and whether
2440 * it is variadic or not.
2441 */
2442 final ParameterList getParameterList()
2443 {
2444 if (type)
2445 {
2446 TypeFunction fdtype = type.isTypeFunction();
2447 if (fdtype) // Could also be TypeError
2448 return fdtype.parameterList;
2449 }
2450
2451 return ParameterList(null, VarArg.none);
2452 }
2453
2454 /**********************************
2455 * Generate a FuncDeclaration for a runtime library function.
2456 */
2457 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2458 {
2459 return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc);
2460 }
2461
2462 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2463 {
2464 FuncDeclaration fd;
2465 TypeFunction tf;
2466 Dsymbol s;
2467 __gshared DsymbolTable st = null;
2468
2469 //printf("genCfunc(name = '%s')\n", id.toChars());
2470 //printf("treturn\n\t"); treturn.print();
2471
2472 // See if already in table
2473 if (!st)
2474 st = new DsymbolTable();
2475 s = st.lookup(id);
2476 if (s)
2477 {
2478 fd = s.isFuncDeclaration();
2479 assert(fd);
2480 assert(fd.type.nextOf().equals(treturn));
2481 }
2482 else
2483 {
2484 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2485 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2486 fd.visibility = Visibility(Visibility.Kind.public_);
2487 fd._linkage = LINK.c;
2488
2489 st.insert(fd);
2490 }
2491 return fd;
2492 }
2493
2494 /+
2495 + Checks the parameter and return types iff this is a `main` function.
2496 +
2497 + The following signatures are allowed for a `D main`:
2498 + - Either no or a single parameter of type `string[]`
2499 + - Return type is either `void`, `int` or `noreturn`
2500 +
2501 + The following signatures are standard C:
2502 + - `int main()`
2503 + - `int main(int, char**)`
2504 +
2505 + This function accepts the following non-standard extensions:
2506 + - `char** envp` as a third parameter
2507 + - `void` / `noreturn` as return type
2508 +
2509 + This function will issue errors for unexpected arguments / return types.
2510 +/
2511 extern (D) final void checkMain()
2512 {
2513 if (ident != Id.main || isMember() || isNested())
2514 return; // Not a main function
2515
2516 TypeFunction tf = type.toTypeFunction();
2517
2518 Type retType = tf.nextOf();
2519 if (!retType)
2520 {
2521 // auto main(), check after semantic
2522 assert(this.inferRetType);
2523 return;
2524 }
2525
2526 /// Checks whether `t` is equivalent to `char**`
2527 /// Ignores qualifiers and treats enums according to their base type
2528 static bool isCharPtrPtr(Type t)
2529 {
2530 auto tp = t.toBasetype().isTypePointer();
2531 if (!tp)
2532 return false;
2533
2534 tp = tp.next.toBasetype().isTypePointer();
2535 if (!tp)
2536 return false;
2537
2538 return tp.next.toBasetype().ty == Tchar;
2539 }
2540
2541 // Neither of these qualifiers is allowed because they affect the ABI
2542 enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2543
2544 const nparams = tf.parameterList.length;
2545 bool argerr;
2546
2547 const linkage = resolvedLinkage();
2548 if (linkage == LINK.d)
2549 {
2550 if (nparams == 1)
2551 {
2552 auto fparam0 = tf.parameterList[0];
2553 auto t = fparam0.type.toBasetype();
2554 if (t.ty != Tarray ||
2555 t.nextOf().ty != Tarray ||
2556 t.nextOf().nextOf().ty != Tchar ||
2557 fparam0.storageClass & invalidSTC)
2558 {
2559 argerr = true;
2560 }
2561 }
2562
2563 if (tf.parameterList.varargs || nparams >= 2 || argerr)
2564 .error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars);
2565 }
2566
2567 else if (linkage == LINK.c)
2568 {
2569 if (nparams == 2 || nparams == 3)
2570 {
2571 // Argument count must be int
2572 auto argCount = tf.parameterList[0];
2573 argerr |= !!(argCount.storageClass & invalidSTC);
2574 argerr |= argCount.type.toBasetype().ty != Tint32;
2575
2576 // Argument pointer must be char**
2577 auto argPtr = tf.parameterList[1];
2578 argerr |= !!(argPtr.storageClass & invalidSTC);
2579 argerr |= !isCharPtrPtr(argPtr.type);
2580
2581 // `char** environ` is a common extension, see J.5.1 of the C standard
2582 if (nparams == 3)
2583 {
2584 auto envPtr = tf.parameterList[2];
2585 argerr |= !!(envPtr.storageClass & invalidSTC);
2586 argerr |= !isCharPtrPtr(envPtr.type);
2587 }
2588 }
2589 else
2590 argerr = nparams != 0;
2591
2592 // Disallow variadic main() - except for K&R declarations in C files.
2593 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2594 if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2595 argerr |= true;
2596
2597 if (argerr)
2598 {
2599 .error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars);
2600 loc.errorSupplemental("`main()`");
2601 loc.errorSupplemental("`main(int argc, char** argv)`");
2602 loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2603 }
2604 }
2605 else
2606 return; // Neither C nor D main, ignore (should probably be an error)
2607
2608 // Allow enums with appropriate base types (same ABI)
2609 retType = retType.toBasetype();
2610
2611 if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2612 .error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars());
2613 }
2614
2615 /***********************************************
2616 * Check all return statements for a function to verify that returning
2617 * using NRVO is possible.
2618 *
2619 * Returns:
2620 * `false` if the result cannot be returned by hidden reference.
2621 */
2622 extern (D) final bool checkNRVO()
2623 {
2624 if (!isNRVO() || returns is null)
2625 return false;
2626
2627 auto tf = type.toTypeFunction();
2628 if (tf.isref)
2629 return false;
2630
2631 foreach (rs; *returns)
2632 {
2633 if (auto ve = rs.exp.isVarExp())
2634 {
2635 auto v = ve.var.isVarDeclaration();
2636 if (!v || v.isReference())
2637 return false;
2638 else if (nrvo_var is null)
2639 {
2640 // Variables in the data segment (e.g. globals, TLS or not),
2641 // parameters and closure variables cannot be NRVOed.
2642 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2643 return false;
2644 if (v.nestedrefs.length && needsClosure())
2645 return false;
2646 // don't know if the return storage is aligned
2647 version (MARS)
2648 {
2649 if (alignSectionVars && (*alignSectionVars).contains(v))
2650 return false;
2651 }
2652 // The variable type needs to be equivalent to the return type.
2653 if (!v.type.equivalent(tf.next))
2654 return false;
2655 //printf("Setting nrvo to %s\n", v.toChars());
2656 nrvo_var = v;
2657 }
2658 else if (nrvo_var != v)
2659 return false;
2660 }
2661 else //if (!exp.isLvalue()) // keep NRVO-ability
2662 return false;
2663 }
2664 return true;
2665 }
2666
2667 override final inout(FuncDeclaration) isFuncDeclaration() inout
2668 {
2669 return this;
2670 }
2671
2672 inout(FuncDeclaration) toAliasFunc() inout
2673 {
2674 return this;
2675 }
2676
2677 override void accept(Visitor v)
2678 {
2679 v.visit(this);
2680 }
2681 }
2682
2683 /********************************************************
2684 * Generate Expression to call the invariant.
2685 * Input:
2686 * ad aggregate with the invariant
2687 * vthis variable with 'this'
2688 * Returns:
2689 * void expression that calls the invariant
2690 */
2691 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
2692 {
2693 Expression e = null;
2694 // Call invariant directly only if it exists
2695 FuncDeclaration inv = ad.inv;
2696 ClassDeclaration cd = ad.isClassDeclaration();
2697
2698 while (!inv && cd)
2699 {
2700 cd = cd.baseClass;
2701 if (!cd)
2702 break;
2703 inv = cd.inv;
2704 }
2705 if (inv)
2706 {
2707 version (all)
2708 {
2709 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2710 // For the correct mangling,
2711 // run attribute inference on inv if needed.
2712 functionSemantic(inv);
2713 }
2714
2715 //e = new DsymbolExp(Loc.initial, inv);
2716 //e = new CallExp(Loc.initial, e);
2717 //e = e.semantic(sc2);
2718
2719 /* https://issues.dlang.org/show_bug.cgi?id=13113
2720 * Currently virtual invariant calls completely
2721 * bypass attribute enforcement.
2722 * Change the behavior of pre-invariant call by following it.
2723 */
2724 e = new ThisExp(Loc.initial);
2725 e.type = ad.type.addMod(vthis.type.mod);
2726 e = new DotVarExp(Loc.initial, e, inv, false);
2727 e.type = inv.type;
2728 e = new CallExp(Loc.initial, e);
2729 e.type = Type.tvoid;
2730 }
2731 return e;
2732 }
2733
2734 /***************************************************
2735 * Visit each overloaded function/template in turn, and call dg(s) on it.
2736 * Exit when no more, or dg(s) returns nonzero.
2737 *
2738 * Params:
2739 * fstart = symbol to start from
2740 * dg = the delegate to be called on the overload
2741 * sc = context used to check if symbol is accessible (and therefore visible),
2742 * can be null
2743 *
2744 * Returns:
2745 * ==0 continue
2746 * !=0 done (and the return value from the last dg() call)
2747 */
2748 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
2749 {
2750 Dsymbols visited;
2751
2752 int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
2753 {
2754 // Detect cyclic calls.
2755 if (visited.contains(fstart))
2756 return 0;
2757 visited.push(fstart);
2758
2759 Dsymbol next;
2760 for (auto d = fstart; d; d = next)
2761 {
2762 import dmd.access : checkSymbolAccess;
2763 if (auto od = d.isOverDeclaration())
2764 {
2765 /* The scope is needed here to check whether a function in
2766 an overload set was added by means of a private alias (or a
2767 selective import). If the scope where the alias is created
2768 is imported somewhere, the overload set is visible, but the private
2769 alias is not.
2770 */
2771 if (sc)
2772 {
2773 if (checkSymbolAccess(sc, od))
2774 {
2775 if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2776 return r;
2777 }
2778 }
2779 else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2780 return r;
2781 next = od.overnext;
2782 }
2783 else if (auto fa = d.isFuncAliasDeclaration())
2784 {
2785 if (fa.hasOverloads)
2786 {
2787 if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
2788 return r;
2789 }
2790 else if (auto fd = fa.toAliasFunc())
2791 {
2792 if (int r = dg(fd))
2793 return r;
2794 }
2795 else
2796 {
2797 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
2798 break;
2799 }
2800 next = fa.overnext;
2801 }
2802 else if (auto ad = d.isAliasDeclaration())
2803 {
2804 if (sc)
2805 {
2806 if (checkSymbolAccess(sc, ad))
2807 next = ad.toAlias();
2808 }
2809 else
2810 next = ad.toAlias();
2811 if (next == ad)
2812 break;
2813 if (next == fstart)
2814 break;
2815 }
2816 else if (auto td = d.isTemplateDeclaration())
2817 {
2818 if (int r = dg(td))
2819 return r;
2820 next = td.overnext;
2821 }
2822 else if (auto fd = d.isFuncDeclaration())
2823 {
2824 if (int r = dg(fd))
2825 return r;
2826 next = fd.overnext;
2827 }
2828 else if (auto os = d.isOverloadSet())
2829 {
2830 foreach (ds; os.a)
2831 if (int r = dg(ds))
2832 return r;
2833 }
2834 else
2835 {
2836 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
2837 break;
2838 // BUG: should print error message?
2839 }
2840 }
2841 return 0;
2842 }
2843 return overloadApplyRecurse(fstart, dg, sc);
2844 }
2845
2846 /**
2847 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
2848 mismatching modifiers to `buf`.
2849
2850 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
2851 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
2852
2853 Params:
2854 buf = output buffer to write to
2855 lhsMod = modifier on the left-hand side
2856 lhsMod = modifier on the right-hand side
2857
2858 Returns:
2859
2860 A tuple with `isMutable` and `isNotShared` set
2861 if the `lhsMod` is missing those modifiers (compared to rhs).
2862 */
2863 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
2864 {
2865 static struct Mismatches
2866 {
2867 bool isNotShared;
2868 bool isMutable;
2869 }
2870
2871 Mismatches mismatches;
2872
2873 bool bothMutable = ((lhsMod & rhsMod) == 0);
2874 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
2875 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
2876
2877 if (lhsMod & MODFlags.shared_)
2878 buf.writestring("`shared` ");
2879 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
2880 {
2881 buf.writestring("non-shared ");
2882 mismatches.isNotShared = true;
2883 }
2884
2885 if (bothMutable && sharedMismatchOnly)
2886 {
2887 }
2888 else if (lhsMod & MODFlags.immutable_)
2889 buf.writestring("`immutable` ");
2890 else if (lhsMod & MODFlags.const_)
2891 buf.writestring("`const` ");
2892 else if (lhsMod & MODFlags.wild)
2893 buf.writestring("`inout` ");
2894 else
2895 {
2896 buf.writestring("mutable ");
2897 mismatches.isMutable = true;
2898 }
2899
2900 return mismatches;
2901 }
2902
2903 ///
2904 unittest
2905 {
2906 OutBuffer buf;
2907 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
2908 assert(buf[] == "`shared` ");
2909 assert(!mismatches.isNotShared);
2910
2911 buf.setsize(0);
2912 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
2913 assert(buf[] == "non-shared ");
2914 assert(mismatches.isNotShared);
2915
2916 buf.setsize(0);
2917 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
2918 assert(buf[] == "`const` ");
2919 assert(!mismatches.isMutable);
2920
2921 buf.setsize(0);
2922 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
2923 assert(buf[] == "mutable ");
2924 assert(mismatches.isMutable);
2925 }
2926
2927 /**************************************
2928 * Returns an indirect type one step from t.
2929 */
2930 Type getIndirection(Type t)
2931 {
2932 t = t.baseElemOf();
2933 if (t.ty == Tarray || t.ty == Tpointer)
2934 return t.nextOf().toBasetype();
2935 if (t.ty == Taarray || t.ty == Tclass)
2936 return t;
2937 if (t.ty == Tstruct)
2938 return t.hasPointers() ? t : null; // TODO
2939
2940 // should consider TypeDelegate?
2941 return null;
2942 }
2943
2944 /**************************************
2945 * Performs type-based alias analysis between a newly created value and a pre-
2946 * existing memory reference:
2947 *
2948 * Assuming that a reference A to a value of type `ta` was available to the code
2949 * that created a reference B to a value of type `tb`, it returns whether B
2950 * might alias memory reachable from A based on the types involved (either
2951 * directly or via any number of indirections in either A or B).
2952 *
2953 * This relation is not symmetric in the two arguments. For example, a
2954 * a `const(int)` reference can point to a pre-existing `int`, but not the other
2955 * way round.
2956 *
2957 * Examples:
2958 *
2959 * ta, tb, result
2960 * `const(int)`, `int`, `false`
2961 * `int`, `const(int)`, `true`
2962 * `int`, `immutable(int)`, `false`
2963 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
2964 *
2965 * Params:
2966 * ta = value type being referred to
2967 * tb = referred to value type that could be constructed from ta
2968 *
2969 * Returns:
2970 * true if reference to `tb` is isolated from reference to `ta`
2971 */
2972 private bool traverseIndirections(Type ta, Type tb)
2973 {
2974 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
2975
2976 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
2977 {
2978 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
2979 ta = ta.baseElemOf();
2980 tb = tb.baseElemOf();
2981
2982 // First, check if the pointed-to types are convertible to each other such
2983 // that they might alias directly.
2984 static bool mayAliasDirect(Type source, Type target)
2985 {
2986 return
2987 // if source is the same as target or can be const-converted to target
2988 source.constConv(target) != MATCH.nomatch ||
2989 // if target is void and source can be const-converted to target
2990 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
2991 }
2992
2993 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
2994 {
2995 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
2996 return false;
2997 }
2998 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
2999 {
3000 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3001 return true;
3002 }
3003
3004 if (tb.ty == Tclass || tb.ty == Tstruct)
3005 {
3006 /* Traverse the type of each field of the aggregate
3007 */
3008 bool* found = table.getLvalue(tb.deco);
3009 if (*found == true)
3010 return true; // We have already seen this symbol, break the cycle
3011 else
3012 *found = true;
3013
3014 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3015 foreach (v; sym.fields)
3016 {
3017 Type tprmi = v.type.addMod(tb.mod);
3018 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3019 if (!traverse(ta, tprmi, table, reversePass))
3020 return false;
3021 }
3022 }
3023 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3024 {
3025 Type tind = tb.nextOf();
3026 if (!traverse(ta, tind, table, reversePass))
3027 return false;
3028 }
3029 else if (tb.hasPointers())
3030 {
3031 // BUG: consider the context pointer of delegate types
3032 return false;
3033 }
3034
3035 // Still no match, so try breaking up ta if we have not done so yet.
3036 if (!reversePass)
3037 {
3038 scope newTable = AssocArray!(const(char)*, bool)();
3039 return traverse(tb, ta, newTable, true);
3040 }
3041
3042 return true;
3043 }
3044
3045 // To handle arbitrary levels of indirections in both parameters, we
3046 // recursively descend into aggregate members/levels of indirection in both
3047 // `ta` and `tb` while avoiding cycles. Start with the original types.
3048 scope table = AssocArray!(const(char)*, bool)();
3049 const result = traverse(ta, tb, table, false);
3050 //printf(" returns %d\n", result);
3051 return result;
3052 }
3053
3054 /* For all functions between outerFunc and f, mark them as needing
3055 * a closure.
3056 */
3057 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3058 {
3059 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3060 {
3061 FuncDeclaration fy = sx.isFuncDeclaration();
3062 if (fy && fy.closureVars.length)
3063 {
3064 /* fy needs a closure if it has closureVars[],
3065 * because the frame pointer in the closure will be accessed.
3066 */
3067 fy.requiresClosure = true;
3068 }
3069 }
3070 }
3071
3072 /********
3073 * Given a nested function f inside a function outerFunc, check
3074 * if any sibling callers of f have escaped. If so, mark
3075 * all the enclosing functions as needing closures.
3076 * This is recursive: we need to check the callers of our siblings.
3077 * Note that nested functions can only call lexically earlier nested
3078 * functions, so loops are impossible.
3079 * Params:
3080 * f = inner function (nested within outerFunc)
3081 * outerFunc = outer function
3082 * p = for internal recursion use
3083 * Returns:
3084 * true if any closures were needed
3085 */
3086 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3087 {
3088 static struct PrevSibling
3089 {
3090 PrevSibling* p;
3091 FuncDeclaration f;
3092 }
3093
3094 if (f.computedEscapingSiblings)
3095 return f.hasEscapingSiblings;
3096
3097 PrevSibling ps;
3098 ps.p = cast(PrevSibling*)p;
3099 ps.f = f;
3100
3101 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3102 bool bAnyClosures = false;
3103 for (size_t i = 0; i < f.siblingCallers.length; ++i)
3104 {
3105 FuncDeclaration g = f.siblingCallers[i];
3106 if (g.isThis() || g.tookAddressOf)
3107 {
3108 markAsNeedingClosure(g, outerFunc);
3109 bAnyClosures = true;
3110 }
3111
3112 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3113 {
3114 // A parent of the sibling had its address taken.
3115 // Assume escaping of parent affects its children, so needs propagating.
3116 // see https://issues.dlang.org/show_bug.cgi?id=19679
3117 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3118 if (parentFunc && parentFunc.tookAddressOf)
3119 {
3120 markAsNeedingClosure(parentFunc, outerFunc);
3121 bAnyClosures = true;
3122 }
3123 }
3124
3125 PrevSibling* prev = cast(PrevSibling*)p;
3126 while (1)
3127 {
3128 if (!prev)
3129 {
3130 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3131 break;
3132 }
3133 if (prev.f == g)
3134 break;
3135 prev = prev.p;
3136 }
3137 }
3138 f.hasEscapingSiblings = bAnyClosures;
3139 f.computedEscapingSiblings = true;
3140 //printf("\t%d\n", bAnyClosures);
3141 return bAnyClosures;
3142 }
3143
3144 /***********************************************************
3145 * Used as a way to import a set of functions from another scope into this one.
3146 */
3147 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3148 {
3149 FuncDeclaration funcalias;
3150 bool hasOverloads;
3151
3152 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3153 {
3154 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3155 assert(funcalias != this);
3156 this.funcalias = funcalias;
3157
3158 this.hasOverloads = hasOverloads;
3159 if (hasOverloads)
3160 {
3161 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3162 this.hasOverloads = fad.hasOverloads;
3163 }
3164 else
3165 {
3166 // for internal use
3167 assert(!funcalias.isFuncAliasDeclaration());
3168 this.hasOverloads = false;
3169 }
3170 userAttribDecl = funcalias.userAttribDecl;
3171 }
3172
3173 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3174 {
3175 return this;
3176 }
3177
3178 override const(char)* kind() const
3179 {
3180 return "function alias";
3181 }
3182
3183 override inout(FuncDeclaration) toAliasFunc() inout
3184 {
3185 return funcalias.toAliasFunc();
3186 }
3187
3188 override void accept(Visitor v)
3189 {
3190 v.visit(this);
3191 }
3192 }
3193
3194 /***********************************************************
3195 */
3196 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3197 {
3198 TOK tok; // TOK.function_ or TOK.delegate_
3199 Type treq; // target of return type inference
3200
3201 // backend
3202 bool deferToObj;
3203
3204 extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null, StorageClass storage_class = STC.undefined_)
3205 {
3206 super(loc, endloc, null, storage_class, type);
3207 this.ident = id ? id : Id.empty;
3208 this.tok = tok;
3209 this.fes = fes;
3210 // Always infer scope for function literals
3211 // See https://issues.dlang.org/show_bug.cgi?id=20362
3212 this.inferScope = true;
3213 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3214 }
3215
3216 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3217 {
3218 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3219 assert(!s);
3220 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
3221 f.treq = treq; // don't need to copy
3222 FuncDeclaration.syntaxCopy(f);
3223 return f;
3224 }
3225
3226 override bool isNested() const
3227 {
3228 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3229 return (tok != TOK.function_) && !isThis();
3230 }
3231
3232 override inout(AggregateDeclaration) isThis() inout
3233 {
3234 return tok == TOK.delegate_ ? super.isThis() : null;
3235 }
3236
3237 override bool isVirtual() const
3238 {
3239 return false;
3240 }
3241
3242 override bool addPreInvariant()
3243 {
3244 return false;
3245 }
3246
3247 override bool addPostInvariant()
3248 {
3249 return false;
3250 }
3251
3252 /*******************************
3253 * Modify all expression type of return statements to tret.
3254 *
3255 * On function literals, return type may be modified based on the context type
3256 * after its semantic3 is done, in FuncExp::implicitCastTo.
3257 *
3258 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3259 *
3260 * If B to A conversion is convariant that requires offseet adjusting,
3261 * all return statements should be adjusted to return expressions typed A.
3262 */
3263 extern (D) void modifyReturns(Scope* sc, Type tret)
3264 {
3265 import dmd.statement_rewrite_walker;
3266
3267 extern (C++) final class RetWalker : StatementRewriteWalker
3268 {
3269 alias visit = typeof(super).visit;
3270 public:
3271 Scope* sc;
3272 Type tret;
3273 FuncLiteralDeclaration fld;
3274
3275 override void visit(ReturnStatement s)
3276 {
3277 Expression exp = s.exp;
3278 if (exp && !exp.type.equals(tret))
3279 s.exp = exp.implicitCastTo(sc, tret);
3280 }
3281 }
3282
3283 if (semanticRun < PASS.semantic3done)
3284 return;
3285
3286 if (fes)
3287 return;
3288
3289 scope RetWalker w = new RetWalker();
3290 w.sc = sc;
3291 w.tret = tret;
3292 w.fld = this;
3293 fbody.accept(w);
3294
3295 // Also update the inferred function type to match the new return type.
3296 // This is required so the code generator does not try to cast the
3297 // modified returns back to the original type.
3298 if (inferRetType && type.nextOf() != tret)
3299 type.toTypeFunction().next = tret;
3300 }
3301
3302 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3303 {
3304 return this;
3305 }
3306
3307 override const(char)* kind() const
3308 {
3309 // GCC requires the (char*) casts
3310 return (tok != TOK.function_) ? "delegate" : "function";
3311 }
3312
3313 override const(char)* toPrettyChars(bool QualifyTypes = false)
3314 {
3315 if (parent)
3316 {
3317 TemplateInstance ti = parent.isTemplateInstance();
3318 if (ti)
3319 return ti.tempdecl.toPrettyChars(QualifyTypes);
3320 }
3321 return Dsymbol.toPrettyChars(QualifyTypes);
3322 }
3323
3324 override void accept(Visitor v)
3325 {
3326 v.visit(this);
3327 }
3328 }
3329
3330 /***********************************************************
3331 */
3332 extern (C++) final class CtorDeclaration : FuncDeclaration
3333 {
3334 bool isCpCtor;
3335 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
3336 {
3337 super(loc, endloc, Id.ctor, stc, type);
3338 this.isCpCtor = isCpCtor;
3339 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
3340 }
3341
3342 override CtorDeclaration syntaxCopy(Dsymbol s)
3343 {
3344 assert(!s);
3345 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
3346 FuncDeclaration.syntaxCopy(f);
3347 return f;
3348 }
3349
3350 override const(char)* kind() const
3351 {
3352 return isCpCtor ? "copy constructor" : "constructor";
3353 }
3354
3355 override const(char)* toChars() const
3356 {
3357 return "this";
3358 }
3359
3360 override bool isVirtual() const
3361 {
3362 return false;
3363 }
3364
3365 override bool addPreInvariant()
3366 {
3367 return false;
3368 }
3369
3370 override bool addPostInvariant()
3371 {
3372 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3373 }
3374
3375 override inout(CtorDeclaration) isCtorDeclaration() inout
3376 {
3377 return this;
3378 }
3379
3380 override void accept(Visitor v)
3381 {
3382 v.visit(this);
3383 }
3384 }
3385
3386 /***********************************************************
3387 */
3388 extern (C++) final class PostBlitDeclaration : FuncDeclaration
3389 {
3390 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3391 {
3392 super(loc, endloc, id, stc, null);
3393 }
3394
3395 override PostBlitDeclaration syntaxCopy(Dsymbol s)
3396 {
3397 assert(!s);
3398 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
3399 FuncDeclaration.syntaxCopy(dd);
3400 return dd;
3401 }
3402
3403 override bool isVirtual() const
3404 {
3405 return false;
3406 }
3407
3408 override bool addPreInvariant()
3409 {
3410 return false;
3411 }
3412
3413 override bool addPostInvariant()
3414 {
3415 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3416 }
3417
3418 override bool overloadInsert(Dsymbol s)
3419 {
3420 return false; // cannot overload postblits
3421 }
3422
3423 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
3424 {
3425 return this;
3426 }
3427
3428 override void accept(Visitor v)
3429 {
3430 v.visit(this);
3431 }
3432 }
3433
3434 /***********************************************************
3435 */
3436 extern (C++) final class DtorDeclaration : FuncDeclaration
3437 {
3438 extern (D) this(const ref Loc loc, const ref Loc endloc)
3439 {
3440 super(loc, endloc, Id.dtor, STC.undefined_, null);
3441 }
3442
3443 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3444 {
3445 super(loc, endloc, id, stc, null);
3446 }
3447
3448 override DtorDeclaration syntaxCopy(Dsymbol s)
3449 {
3450 assert(!s);
3451 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
3452 FuncDeclaration.syntaxCopy(dd);
3453 return dd;
3454 }
3455
3456 override const(char)* kind() const
3457 {
3458 return "destructor";
3459 }
3460
3461 override const(char)* toChars() const
3462 {
3463 return "~this";
3464 }
3465
3466 override bool isVirtual() const
3467 {
3468 // D dtor's don't get put into the vtbl[]
3469 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
3470 return vtblIndex != -1;
3471 }
3472
3473 override bool addPreInvariant()
3474 {
3475 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3476 }
3477
3478 override bool addPostInvariant()
3479 {
3480 return false;
3481 }
3482
3483 override bool overloadInsert(Dsymbol s)
3484 {
3485 return false; // cannot overload destructors
3486 }
3487
3488 override inout(DtorDeclaration) isDtorDeclaration() inout
3489 {
3490 return this;
3491 }
3492
3493 override void accept(Visitor v)
3494 {
3495 v.visit(this);
3496 }
3497 }
3498
3499 /***********************************************************
3500 */
3501 extern (C++) class StaticCtorDeclaration : FuncDeclaration
3502 {
3503 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3504 {
3505 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
3506 }
3507
3508 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3509 {
3510 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3511 }
3512
3513 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
3514 {
3515 assert(!s);
3516 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
3517 FuncDeclaration.syntaxCopy(scd);
3518 return scd;
3519 }
3520
3521 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
3522 {
3523 return null;
3524 }
3525
3526 override final bool isVirtual() const @nogc nothrow pure @safe
3527 {
3528 return false;
3529 }
3530
3531 override final bool addPreInvariant() @nogc nothrow pure @safe
3532 {
3533 return false;
3534 }
3535
3536 override final bool addPostInvariant() @nogc nothrow pure @safe
3537 {
3538 return false;
3539 }
3540
3541 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
3542 {
3543 return true;
3544 }
3545
3546 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
3547 {
3548 return this;
3549 }
3550
3551 override void accept(Visitor v)
3552 {
3553 v.visit(this);
3554 }
3555 }
3556
3557 /***********************************************************
3558 */
3559 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
3560 {
3561 /// Exclude this constructor from cyclic dependency check
3562 bool standalone;
3563
3564 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3565 {
3566 super(loc, endloc, "_sharedStaticCtor", stc);
3567 }
3568
3569 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
3570 {
3571 assert(!s);
3572 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
3573 FuncDeclaration.syntaxCopy(scd);
3574 return scd;
3575 }
3576
3577 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
3578 {
3579 return this;
3580 }
3581
3582 override void accept(Visitor v)
3583 {
3584 v.visit(this);
3585 }
3586 }
3587
3588 /***********************************************************
3589 */
3590 extern (C++) class StaticDtorDeclaration : FuncDeclaration
3591 {
3592 VarDeclaration vgate; // 'gate' variable
3593
3594 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3595 {
3596 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
3597 }
3598
3599 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3600 {
3601 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3602 }
3603
3604 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
3605 {
3606 assert(!s);
3607 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
3608 FuncDeclaration.syntaxCopy(sdd);
3609 return sdd;
3610 }
3611
3612 override final inout(AggregateDeclaration) isThis() inout
3613 {
3614 return null;
3615 }
3616
3617 override final bool isVirtual() const
3618 {
3619 return false;
3620 }
3621
3622 override final bool hasStaticCtorOrDtor()
3623 {
3624 return true;
3625 }
3626
3627 override final bool addPreInvariant()
3628 {
3629 return false;
3630 }
3631
3632 override final bool addPostInvariant()
3633 {
3634 return false;
3635 }
3636
3637 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
3638 {
3639 return this;
3640 }
3641
3642 override void accept(Visitor v)
3643 {
3644 v.visit(this);
3645 }
3646 }
3647
3648 /***********************************************************
3649 */
3650 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
3651 {
3652 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3653 {
3654 super(loc, endloc, "_sharedStaticDtor", stc);
3655 }
3656
3657 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
3658 {
3659 assert(!s);
3660 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
3661 FuncDeclaration.syntaxCopy(sdd);
3662 return sdd;
3663 }
3664
3665 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
3666 {
3667 return this;
3668 }
3669
3670 override void accept(Visitor v)
3671 {
3672 v.visit(this);
3673 }
3674 }
3675
3676 /***********************************************************
3677 */
3678 extern (C++) final class InvariantDeclaration : FuncDeclaration
3679 {
3680 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
3681 {
3682 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
3683 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
3684 this.fbody = fbody;
3685 }
3686
3687 override InvariantDeclaration syntaxCopy(Dsymbol s)
3688 {
3689 assert(!s);
3690 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
3691 FuncDeclaration.syntaxCopy(id);
3692 return id;
3693 }
3694
3695 override bool isVirtual() const
3696 {
3697 return false;
3698 }
3699
3700 override bool addPreInvariant()
3701 {
3702 return false;
3703 }
3704
3705 override bool addPostInvariant()
3706 {
3707 return false;
3708 }
3709
3710 override inout(InvariantDeclaration) isInvariantDeclaration() inout
3711 {
3712 return this;
3713 }
3714
3715 override void accept(Visitor v)
3716 {
3717 v.visit(this);
3718 }
3719
3720 extern (D) void fixupInvariantIdent(size_t offset)
3721 {
3722 OutBuffer idBuf;
3723 idBuf.writestring("__invariant");
3724 idBuf.print(offset);
3725
3726 ident = Identifier.idPool(idBuf[]);
3727 }
3728 }
3729
3730
3731 /***********************************************************
3732 */
3733 extern (C++) final class UnitTestDeclaration : FuncDeclaration
3734 {
3735 char* codedoc; // for documented unittest
3736
3737 // toObjFile() these nested functions after this one
3738 FuncDeclarations deferredNested;
3739
3740 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
3741 {
3742 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
3743 this.codedoc = codedoc;
3744 }
3745
3746 override UnitTestDeclaration syntaxCopy(Dsymbol s)
3747 {
3748 assert(!s);
3749 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
3750 FuncDeclaration.syntaxCopy(utd);
3751 return utd;
3752 }
3753
3754 override inout(AggregateDeclaration) isThis() inout
3755 {
3756 return null;
3757 }
3758
3759 override bool isVirtual() const
3760 {
3761 return false;
3762 }
3763
3764 override bool addPreInvariant()
3765 {
3766 return false;
3767 }
3768
3769 override bool addPostInvariant()
3770 {
3771 return false;
3772 }
3773
3774 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
3775 {
3776 return this;
3777 }
3778
3779 override void accept(Visitor v)
3780 {
3781 v.visit(this);
3782 }
3783 }
3784
3785 /***********************************************************
3786 */
3787 extern (C++) final class NewDeclaration : FuncDeclaration
3788 {
3789 extern (D) this(const ref Loc loc, StorageClass stc)
3790 {
3791 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
3792 }
3793
3794 override NewDeclaration syntaxCopy(Dsymbol s)
3795 {
3796 assert(!s);
3797 auto f = new NewDeclaration(loc, storage_class);
3798 FuncDeclaration.syntaxCopy(f);
3799 return f;
3800 }
3801
3802 override const(char)* kind() const
3803 {
3804 return "allocator";
3805 }
3806
3807 override bool isVirtual() const
3808 {
3809 return false;
3810 }
3811
3812 override bool addPreInvariant()
3813 {
3814 return false;
3815 }
3816
3817 override bool addPostInvariant()
3818 {
3819 return false;
3820 }
3821
3822 override inout(NewDeclaration) isNewDeclaration() inout
3823 {
3824 return this;
3825 }
3826
3827 override void accept(Visitor v)
3828 {
3829 v.visit(this);
3830 }
3831 }
3832
3833 /**************************************
3834 * When a traits(compiles) is used on a function literal call
3835 * we need to take into account if the body of the function
3836 * violates any attributes, however, we must not affect the
3837 * attribute inference on the outer function. The attributes
3838 * of the function literal still need to be inferred, therefore
3839 * we need a way to check for the scope that the traits compiles
3840 * introduces.
3841 *
3842 * Params:
3843 * sc = scope to be checked for
3844 *
3845 * Returns: `true` if the provided scope is the root
3846 * of the traits compiles list of scopes.
3847 */
3848 bool isRootTraitsCompilesScope(Scope* sc)
3849 {
3850 return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
3851 }
3852
3853 /**************************************
3854 * A statement / expression in this scope is not `@safe`,
3855 * so mark the enclosing function as `@system`
3856 *
3857 * Params:
3858 * sc = scope that the unsafe statement / expression is in
3859 * gag = surpress error message (used in escape.d)
3860 * loc = location of error
3861 * fmt = printf-style format string
3862 * arg0 = (optional) argument for first %s format specifier
3863 * arg1 = (optional) argument for second %s format specifier
3864 * arg2 = (optional) argument for third %s format specifier
3865 * Returns: whether there's a safe error
3866 */
3867 bool setUnsafe(Scope* sc,
3868 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
3869 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
3870 {
3871 if (sc.intypeof)
3872 return false; // typeof(cast(int*)0) is safe
3873
3874 if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
3875 return false;
3876
3877 if (!sc.func)
3878 {
3879 if (sc.varDecl)
3880 {
3881 if (sc.varDecl.storage_class & STC.safe)
3882 {
3883 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
3884 return true;
3885 }
3886 else if (!(sc.varDecl.storage_class & STC.trusted))
3887 {
3888 sc.varDecl.storage_class |= STC.system;
3889 sc.varDecl.systemInferred = true;
3890 }
3891 }
3892 return false;
3893 }
3894
3895
3896 if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
3897 {
3898 if (sc.func.isSafeBypassingInference())
3899 {
3900 // Message wil be gagged, but still call error() to update global.errors and for
3901 // -verrors=spec
3902 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
3903 return true;
3904 }
3905 return false;
3906 }
3907
3908 return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
3909 }
3910
3911 /***************************************
3912 * Like `setUnsafe`, but for safety errors still behind preview switches
3913 *
3914 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
3915 * the behavior changes based on the setting:
3916 *
3917 * - In case of `-revert=fs`, it does nothing.
3918 * - In case of `-preview=fs`, it's the same as `setUnsafe`
3919 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
3920 *
3921 * Params:
3922 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
3923 * fs = feature state from the preview flag
3924 * gag = surpress error message
3925 * loc = location of error
3926 * msg = printf-style format string
3927 * arg0 = (optional) argument for first %s format specifier
3928 * arg1 = (optional) argument for second %s format specifier
3929 * arg2 = (optional) argument for third %s format specifier
3930 * Returns: whether an actual safe error (not deprecation) occured
3931 */
3932 bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
3933 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
3934 {
3935 //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
3936 with (FeatureState) final switch (fs)
3937 {
3938 case disabled:
3939 return false;
3940
3941 case enabled:
3942 return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
3943
3944 case default_:
3945 if (!sc.func)
3946 return false;
3947 if (sc.func.isSafeBypassingInference())
3948 {
3949 if (!gag && !sc.isDeprecated())
3950 {
3951 deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
3952 }
3953 }
3954 else if (!sc.func.safetyViolation)
3955 {
3956 import dmd.func : AttributeViolation;
3957 sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
3958 }
3959 return false;
3960 }
3961 }
3962
3963 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
3964 ///
3965 /// Has two modes:
3966 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
3967 /// - a call to a function without the attribute, which is a special case, because in that case,
3968 /// that function might recursively also have a `AttributeViolation`. This way, in case
3969 /// of a big call stack, the error can go down all the way to the root cause.
3970 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
3971 struct AttributeViolation
3972 {
3973 /// location of error
3974 Loc loc = Loc.init;
3975 /// printf-style format string
3976 const(char)* fmtStr = null;
3977 /// Arguments for up to two `%s` format specifiers in format string
3978 RootObject arg0 = null;
3979 /// ditto
3980 RootObject arg1 = null;
3981 /// ditto
3982 RootObject arg2 = null;
3983 }
3984
3985 /// Print the reason why `fd` was inferred `@system` as a supplemental error
3986 /// Params:
3987 /// fd = function to check
3988 /// maxDepth = up to how many functions deep to report errors
3989 /// deprecation = print deprecations instead of errors
3990 /// stc = storage class of attribute to check
3991 void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
3992 {
3993 auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
3994
3995 AttributeViolation* s;
3996 const(char)* attr;
3997 if (stc & STC.safe)
3998 {
3999 s = fd.safetyViolation;
4000 attr = "@safe";
4001 }
4002 else if (stc & STC.pure_)
4003 {
4004 s = fd.pureViolation;
4005 attr = "pure";
4006 }
4007 else if (stc & STC.nothrow_)
4008 {
4009 s = fd.nothrowViolation;
4010 attr = "nothrow";
4011 }
4012 else if (stc & STC.nogc)
4013 {
4014 s = fd.nogcViolation;
4015 attr = "@nogc";
4016 }
4017
4018 if (s)
4019 {
4020 if (s.fmtStr)
4021 {
4022 errorFunc(s.loc, deprecation ?
4023 "which wouldn't be `%s` because of:" :
4024 "which wasn't inferred `%s` because of:", attr);
4025 if (stc == STC.nogc || stc == STC.pure_)
4026 {
4027 auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
4028 errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
4029 }
4030 else
4031 {
4032 errorFunc(s.loc, s.fmtStr,
4033 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
4034 }
4035 }
4036 else if (auto sa = s.arg0.isDsymbol())
4037 {
4038 if (FuncDeclaration fd2 = sa.isFuncDeclaration())
4039 {
4040 if (maxDepth > 0)
4041 {
4042 errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
4043 errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);
4044 }
4045 }
4046 }
4047 }
4048 }