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