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