2 * Performs the semantic3 stage, which deals with function bodies.
4 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d)
8 * Documentation: https://dlang.org/phobos/dmd_semantic3.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic3.d
14 import core
.stdc
.stdio
;
15 import core
.stdc
.string
;
19 import dmd
.arraytypes
;
20 import dmd
.astcodegen
;
28 import dmd
.declaration
;
31 import dmd
.dinterpret
;
36 import dmd
.dsymbolsem
;
41 import dmd
.expression
;
42 import dmd
.expressionsem
;
47 import dmd
.identifier
;
60 import dmd
.root
.filename
;
61 import dmd
.common
.outbuffer
;
63 import dmd
.rootobject
;
65 import dmd
.sideeffect
;
66 import dmd
.statementsem
;
67 import dmd
.staticassert
;
72 import dmd
.templateparamsem
;
79 /*************************************
80 * Does semantic analysis on function bodies.
82 extern(C
++) void semantic3(Dsymbol dsym
, Scope
* sc
)
84 scope v
= new Semantic3Visitor(sc
);
88 private extern(C
++) final class Semantic3Visitor
: Visitor
90 alias visit
= Visitor
.visit
;
93 this(Scope
* sc
) scope @safe
98 override void visit(Dsymbol
) {}
100 override void visit(TemplateInstance tempinst
)
104 printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", tempinst
.toChars(), tempinst
.semanticRun
);
106 //if (toChars()[0] == 'D') *(char*)0=0;
107 if (tempinst
.semanticRun
>= PASS
.semantic3
)
109 tempinst
.semanticRun
= PASS
.semantic3
;
110 if (tempinst
.errors ||
!tempinst
.members
)
113 TemplateDeclaration tempdecl
= tempinst
.tempdecl
.isTemplateDeclaration();
116 sc
= tempdecl
._scope
;
117 sc
= sc
.push(tempinst
.argsym
);
118 sc
= sc
.push(tempinst
);
120 sc
.minst
= tempinst
.minst
;
122 int needGagging
= (tempinst
.gagged
&& !global
.gag
);
123 uint olderrors
= global
.errors
;
124 int oldGaggedErrors
= -1; // dead-store to prevent spurious warning
125 /* If this is a gagged instantiation, gag errors.
126 * Future optimisation: If the results are actually needed, errors
127 * would already be gagged, so we don't really need to run semantic
131 oldGaggedErrors
= global
.startGagging();
133 for (size_t i
= 0; i
< tempinst
.members
.length
; i
++)
135 Dsymbol s
= (*tempinst
.members
)[i
];
137 if (tempinst
.gagged
&& global
.errors
!= olderrors
)
141 if (global
.errors
!= olderrors
)
143 if (!tempinst
.errors
)
145 if (!tempdecl
.literal
)
146 .error(tempinst
.loc
, "%s `%s` error instantiating", tempinst
.kind
, tempinst
.toPrettyChars
);
148 tempinst
.tinst
.printInstantiationTrace();
150 tempinst
.errors
= true;
153 global
.endGagging(oldGaggedErrors
);
159 override void visit(TemplateMixin tmix
)
161 if (tmix
.semanticRun
>= PASS
.semantic3
)
163 tmix
.semanticRun
= PASS
.semantic3
;
166 printf("TemplateMixin.semantic3('%s')\n", tmix
.toChars());
171 sc
= sc
.push(tmix
.argsym
);
174 uint olderrors
= global
.errors
;
176 for (size_t i
= 0; i
< tmix
.members
.length
; i
++)
178 Dsymbol s
= (*tmix
.members
)[i
];
182 if (global
.errors
!= olderrors
)
183 errorSupplemental(tmix
.loc
, "parent scope from here: `mixin %s`", tmix
.toChars());
189 override void visit(Module mod
)
191 //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
192 if (mod
.semanticRun
!= PASS
.semantic2done
)
194 mod
.semanticRun
= PASS
.semantic3
;
195 // Note that modules get their own scope, from scratch.
196 // This is so regardless of where in the syntax a module
197 // gets imported, it is unaffected by context.
198 Scope
* sc
= Scope
.createGlobal(mod
, global
.errorSink
); // create root scope
199 //printf("Module = %p\n", sc.scopesym);
202 // Pass 3 semantic routines: do initializers and function bodies
203 for (size_t i
= 0; i
< mod
.members
.length
; i
++)
205 Dsymbol s
= (*mod
.members
)[i
];
206 //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
209 mod
.runDeferredSemantic2();
212 if (mod
.userAttribDecl
)
214 mod
.userAttribDecl
.semantic3(sc
);
218 mod
.semanticRun
= PASS
.semantic3done
;
221 override void visit(FuncDeclaration funcdecl
)
223 //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", funcdecl.kind(), funcdecl.toChars(), sc);
224 /* Determine if function should add `return 0;`
228 //printf("addReturn0()\n");
229 auto f
= funcdecl
.type
.isTypeFunction();
232 if (sc
.flags
& SCOPE
.Cfile
&& funcdecl
.isCMain() && f
.next
.ty
== Tint32
)
235 return f
.next
.ty
== Tvoid
&& (funcdecl
.isMain() || funcdecl
.isCMain());
238 VarDeclaration _arguments
= null;
240 if (!funcdecl
.parent
)
244 //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
247 if (funcdecl
.errors ||
isError(funcdecl
.parent
))
249 funcdecl
.errors
= true;
251 // Mark that the return type could not be inferred
252 if (funcdecl
.inferRetType
)
254 assert(funcdecl
.type
);
255 auto tf
= funcdecl
.type
.isTypeFunction();
257 // Only change the return type s.t. other analysis is
258 // still possible e.g. missmatched parameter types
260 tf
.next
= Type
.terror
;
264 //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), funcdecl, sc, funcdecl.loc.toChars());
266 //printf("storage class = x%x %x\n", sc.stc, storage_class);
267 //{ static int x; if (++x == 2) *(char*)0=0; }
268 //printf("\tlinkage = %d\n", sc.linkage);
270 if (funcdecl
.ident
== Id
.assign
&& !funcdecl
.inuse
)
272 if (funcdecl
.storage_class
& STC
.inference
)
274 /* https://issues.dlang.org/show_bug.cgi?id=15044
275 * For generated opAssign function, any errors
276 * from its body need to be gagged.
278 uint oldErrors
= global
.startGagging();
280 funcdecl
.semantic3(sc
);
282 if (global
.endGagging(oldErrors
)) // if errors happened
284 // Disable generated opAssign, because some members forbid identity assignment.
285 funcdecl
.storage_class |
= STC
.disable
;
286 funcdecl
.fbody
= null; // remove fbody which contains the error
287 funcdecl
.hasSemantic3Errors
= false;
293 //printf(" sc.incontract = %d\n", (sc.flags & SCOPE.contract));
294 if (funcdecl
.semanticRun
>= PASS
.semantic3
)
296 funcdecl
.semanticRun
= PASS
.semantic3
;
297 funcdecl
.hasSemantic3Errors
= false;
299 if (!funcdecl
.type || funcdecl
.type
.ty
!= Tfunction
)
301 TypeFunction f
= cast(TypeFunction
)funcdecl
.type
;
302 if (!funcdecl
.inferRetType
&& f
.next
.ty
== Terror
)
305 if (!funcdecl
.fbody
&& funcdecl
.inferRetType
&& !f
.next
)
307 .error(funcdecl
.loc
, "%s `%s` has no function body with return type inference", funcdecl
.kind
, funcdecl
.toPrettyChars
);
311 uint oldErrors
= global
.errors
;
312 auto fds
= FuncDeclSem3(funcdecl
,sc
);
314 fds
.checkInContractOverrides();
316 // Remember whether we need to generate an 'out' contract.
317 immutable bool needEnsure
= FuncDeclaration
.needsFensure(funcdecl
);
319 if (funcdecl
.fbody || funcdecl
.frequires || needEnsure
)
321 /* Symbol table into which we place parameters and nested functions,
322 * solely to diagnose name collisions.
324 funcdecl
.localsymtab
= new DsymbolTable();
326 // Establish function scope
327 auto ss
= new ScopeDsymbol(funcdecl
.loc
, null);
328 // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
329 ss
.parent
= sc
.inner().scopesym
;
330 ss
.endlinnum
= funcdecl
.endloc
.linnum
;
331 Scope
* sc2
= sc
.push(ss
);
333 sc2
.parent
= funcdecl
;
334 sc2
.ctorflow
.callSuper
= CSX
.none
;
336 sc2
.scontinue
= null;
338 sc2
.fes
= funcdecl
.fes
;
339 sc2
.linkage
= funcdecl
.isCsymbol() ? LINK
.c
: LINK
.d
;
340 sc2
.stc &= STC
.flowThruFunction
;
341 sc2
.visibility
= Visibility(Visibility
.Kind
.public_
);
342 sc2
.explicitVisibility
= 0;
343 sc2
.aligndecl
= null;
344 if (funcdecl
.ident
!= Id
.require
&& funcdecl
.ident
!= Id
.ensure
)
345 sc2
.flags
= sc
.flags
& ~SCOPE
.contract
;
349 sc2
.inDefaultArg
= false;
350 sc2
.userAttribDecl
= null;
351 if (sc2
.intypeof
== 1)
353 sc2
.ctorflow
.fieldinit
= null;
355 /* Note: When a lambda is defined immediately under aggregate member
356 * scope, it should be contextless due to prevent interior pointers.
358 * // dg points 'this' - its interior pointer
359 * class C { int x; void delegate() dg = (){ this.x = 1; }; }
361 * However, lambdas could be used inside typeof, in order to check
362 * some expressions validity at compile time. For such case the lambda
363 * body can access aggregate instance members.
365 * class C { int x; static assert(is(typeof({ this.x = 1; }))); }
367 * To properly accept it, mark these lambdas as member functions.
369 if (auto fld = funcdecl
.isFuncLiteralDeclaration())
371 if (auto ad
= funcdecl
.isMember2())
375 if (fld.tok
== TOK
.delegate_
)
376 .error(funcdecl
.loc
, "%s `%s` cannot be %s members", funcdecl
.kind
, funcdecl
.toPrettyChars
, ad
.kind());
378 fld.tok
= TOK
.function_
;
382 if (fld.tok
!= TOK
.function_
)
383 fld.tok
= TOK
.delegate_
;
388 declareThis(funcdecl
, sc2
);
390 // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710
391 // No compiler supports this, and there was never any spec for it.
392 // @@@DEPRECATED_2.116@@@
393 // Deprecated in 2.096, can be made an error in 2.116.
394 // The deprecation period is longer than usual as dual-context
395 // functions may be widely used by dmd-compiled projects.
396 // It also gives more time for the implementation of dual-context
397 // functions to be reworked as a frontend-only feature.
398 if (funcdecl
.hasDualContext())
400 .deprecation(funcdecl
.loc
, "%s `%s` function requires a dual-context, which is deprecated", funcdecl
.kind
, funcdecl
.toPrettyChars
);
401 if (auto ti
= sc2
.parent ? sc2
.parent
.isInstantiated() : null)
402 ti
.printInstantiationTrace(Classification
.deprecation
);
405 //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis);
406 //if (vthis) printf("\tvthis.type = %s\n", vthis.type.toChars());
408 // Declare hidden variable _arguments[] and _argptr
409 if (f
.parameterList
.varargs
== VarArg
.variadic
)
411 if (f
.linkage
== LINK
.d
)
413 // Variadic arguments depend on Typeinfo being defined.
414 if (!global
.params
.useTypeInfo ||
!Type
.dtypeinfo ||
!Type
.typeinfotypelist
)
416 if (!global
.params
.useTypeInfo
)
419 .error(funcdecl
.loc
, "%s `%s` D-style variadic functions cannot be used with `-fno-rtti`", funcdecl
.kind
, funcdecl
.toPrettyChars
);
421 .error(funcdecl
.loc
, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl
.kind
, funcdecl
.toPrettyChars
);
423 else if (!Type
.typeinfotypelist
)
424 .error(funcdecl
.loc
, "%s `%s` `object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions", funcdecl
.kind
, funcdecl
.toPrettyChars
);
426 .error(funcdecl
.loc
, "%s `%s` `object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions", funcdecl
.kind
, funcdecl
.toPrettyChars
);
430 // Declare _arguments[]
431 funcdecl
.v_arguments
= new VarDeclaration(funcdecl
.loc
, Type
.typeinfotypelist
.type
, Id
._arguments_typeinfo
, null);
432 funcdecl
.v_arguments
.storage_class |
= STC
.temp | STC
.parameter
;
433 funcdecl
.v_arguments
.dsymbolSemantic(sc2
);
434 sc2
.insert(funcdecl
.v_arguments
);
435 funcdecl
.v_arguments
.parent
= funcdecl
;
437 //Type t = Type.dtypeinfo.type.constOf().arrayOf();
438 Type t
= Type
.dtypeinfo
.type
.arrayOf();
439 _arguments
= new VarDeclaration(funcdecl
.loc
, t
, Id
._arguments
, null);
440 _arguments
.storage_class |
= STC
.temp
;
441 _arguments
.dsymbolSemantic(sc2
);
442 sc2
.insert(_arguments
);
443 _arguments
.parent
= funcdecl
;
445 if (f
.linkage
== LINK
.d || f
.parameterList
.length
)
448 Type t
= target
.va_listType(funcdecl
.loc
, sc
);
449 // Init is handled in FuncDeclaration_toObjFile
450 funcdecl
.v_argptr
= new VarDeclaration(funcdecl
.loc
, t
, Id
._argptr
, new VoidInitializer(funcdecl
.loc
));
451 funcdecl
.v_argptr
.storage_class |
= STC
.temp
;
452 funcdecl
.v_argptr
.dsymbolSemantic(sc2
);
453 sc2
.insert(funcdecl
.v_argptr
);
454 funcdecl
.v_argptr
.parent
= funcdecl
;
458 /* Declare all the function parameters as variables
459 * and install them in parameters[]
461 if (const nparams
= f
.parameterList
.length
)
463 /* parameters[] has all the tuples removed, as the back end
464 * doesn't know about tuples
466 funcdecl
.parameters
= new VarDeclarations();
467 funcdecl
.parameters
.reserve(nparams
);
468 foreach (i
, fparam
; f
.parameterList
)
470 Identifier id
= fparam
.ident
;
471 StorageClass
stc = 0;
474 /* Generate identifier for un-named parameter,
475 * because we need it later on.
477 fparam
.ident
= id
= Identifier
.generateId("__param_", i
);
480 Type vtype
= fparam
.type
;
481 auto v
= new VarDeclaration(fparam
.loc
, vtype
, id
, null);
482 //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars());
483 stc |
= STC
.parameter
;
484 if (f
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
)
489 stc |
= fparam
.storageClass
& (STC
.IOR | STC
.return_ | STC
.scope_ | STC
.lazy_ | STC
.final_ | STC
.TYPECTOR | STC
.nodtor | STC
.returnScope | STC
.register
);
490 v
.storage_class
= stc;
491 v
.dsymbolSemantic(sc2
);
494 .error(funcdecl
.loc
, "%s `%s` parameter `%s.%s` is already defined", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars(), v
.toChars());
495 funcdecl
.errors
= true;
498 funcdecl
.parameters
.push(v
);
499 funcdecl
.localsymtab
.insert(v
);
501 if (fparam
.userAttribDecl
)
502 v
.userAttribDecl
= fparam
.userAttribDecl
;
506 // Declare the tuple symbols and put them in the symbol table,
507 // but not in parameters[].
508 if (f
.parameterList
.parameters
)
509 foreach (fparam
; *f
.parameterList
.parameters
)
512 continue; // never used, so ignore
514 if (fparam
.type
.ty
!= Ttuple
)
517 TypeTuple t
= cast(TypeTuple
)fparam
.type
;
518 size_t dim
= Parameter
.dim(t
.arguments
);
519 auto exps
= new Objects(dim
);
520 foreach (j
; 0 .. dim
)
522 Parameter narg
= Parameter
.getNth(t
.arguments
, j
);
525 VarDeclaration v
= sc2
.search(Loc
.initial
, narg
.ident
, pscopesym
).isVarDeclaration();
527 (*exps
)[j
] = new VarExp(v
.loc
, v
);
529 assert(fparam
.ident
);
530 auto v
= new TupleDeclaration(funcdecl
.loc
, fparam
.ident
, exps
);
531 //printf("declaring tuple %s\n", v.toChars());
534 .error(funcdecl
.loc
, "%s `%s` parameter `%s.%s` is already defined", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars(), v
.toChars());
535 funcdecl
.localsymtab
.insert(v
);
539 // Precondition invariant
540 Statement fpreinv
= null;
541 if (funcdecl
.addPreInvariant())
543 Expression e
= addInvariant(funcdecl
.isThis(), funcdecl
.vthis
);
545 fpreinv
= new ExpStatement(Loc
.initial
, e
);
548 // Postcondition invariant
549 Statement fpostinv
= null;
550 if (funcdecl
.addPostInvariant())
552 Expression e
= addInvariant(funcdecl
.isThis(), funcdecl
.vthis
);
554 fpostinv
= new ExpStatement(Loc
.initial
, e
);
557 // Pre/Postcondition contract
559 funcdecl
.buildEnsureRequire();
562 if (needEnsure || funcdecl
.addPostInvariant())
564 /* https://issues.dlang.org/show_bug.cgi?id=3657
565 * Set the correct end line number for fensure scope.
567 uint fensure_endlin
= funcdecl
.endloc
.linnum
;
568 if (funcdecl
.fensure
)
569 if (auto s
= funcdecl
.fensure
.isScopeStatement())
570 fensure_endlin
= s
.endloc
.linnum
;
572 if ((needEnsure
&& global
.params
.useOut
== CHECKENABLE
.on
) || fpostinv
)
574 funcdecl
.returnLabel
= funcdecl
.searchLabel(Id
.returnLabel
, Loc
.initial
);
577 // scope of out contract (need for vresult.semantic)
578 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
579 sym
.parent
= sc2
.scopesym
;
580 sym
.endlinnum
= fensure_endlin
;
581 scout
= sc2
.push(sym
);
586 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
587 sym
.parent
= sc2
.scopesym
;
588 sym
.endlinnum
= funcdecl
.endloc
.linnum
;
591 auto ad2
= funcdecl
.isMemberLocal();
593 /* If this is a class constructor
595 if (ad2
&& funcdecl
.isCtorDeclaration())
597 sc2
.ctorflow
.allocFieldinit(ad2
.fields
.length
);
598 foreach (v
; ad2
.fields
)
604 bool inferRef
= (f
.isref
&& (funcdecl
.storage_class
& STC
.auto_
));
606 funcdecl
.fbody
= funcdecl
.fbody
.statementSemantic(sc2
);
608 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, new Statements());
610 if (funcdecl
.isNaked())
612 fpreinv
= null; // can't accommodate with no stack frame
616 assert(funcdecl
.type
== f ||
(funcdecl
.type
.ty
== Tfunction
&& f
.purity
== PURE
.impure
&& (cast(TypeFunction
)funcdecl
.type
).purity
>= PURE
.fwdref
));
617 f
= cast(TypeFunction
)funcdecl
.type
;
619 if (funcdecl
.inferRetType
)
621 // If no return type inferred yet, then infer a void
624 if (f
.checkRetType(funcdecl
.loc
))
625 funcdecl
.fbody
= new ErrorStatement();
627 funcdecl
.checkMain(); // Check main() parameters and return type
631 f
.next
.checkComplexTransition(funcdecl
.loc
, sc
);
633 if (funcdecl
.returns
&& !funcdecl
.fbody
.isErrorStatement())
635 for (size_t i
= 0; i
< funcdecl
.returns
.length
;)
637 Expression exp
= (*funcdecl
.returns
)[i
].exp
;
638 if (exp
.op
== EXP
.variable
&& (cast(VarExp
)exp
).var
== funcdecl
.vresult
)
641 exp
.type
= Type
.tint32
;
644 // Remove `return vresult;` from returns
645 funcdecl
.returns
.remove(i
);
648 if (inferRef
&& f
.isref
&& !exp
.type
.constConv(f
.next
)) // https://issues.dlang.org/show_bug.cgi?id=13336
653 if (f
.isref
) // Function returns a reference
655 if (funcdecl
.storage_class
& STC
.auto_
)
656 funcdecl
.storage_class
&= ~STC
.auto_
;
660 if (!target
.isReturnOnStack(f
, funcdecl
.needThis()) ||
!funcdecl
.checkNRVO())
661 funcdecl
.isNRVO
= false;
663 if (funcdecl
.fbody
.isErrorStatement())
666 else if (funcdecl
.isStaticCtorDeclaration())
668 /* It's a static constructor. Ensure that all
669 * ctor consts were initialized.
671 ScopeDsymbol pd
= funcdecl
.toParent().isScopeDsymbol();
672 for (size_t i
= 0; i
< pd
.members
.length
; i
++)
674 Dsymbol s
= (*pd
.members
)[i
];
675 s
.checkCtorConstInit();
678 else if (ad2
&& funcdecl
.isCtorDeclaration())
680 ClassDeclaration cd
= ad2
.isClassDeclaration();
682 // Verify that all the ctorinit fields got initialized
683 if (!(sc2
.ctorflow
.callSuper
& CSX
.this_ctor
))
685 foreach (i
, v
; ad2
.fields
)
687 if (v
.isThisDeclaration())
691 /* Current bugs in the flow analysis:
692 * 1. union members should not produce error messages even if
694 * 2. structs should recognize delegating opAssign calls as well
695 * as delegating calls to other constructors
697 if (v
.isCtorinit() && !v
.type
.isMutable() && cd
)
698 .error(funcdecl
.loc
, "%s `%s` missing initializer for %s field `%s`", funcdecl
.kind
, funcdecl
.toPrettyChars
, MODtoChars(v
.type
.mod
), v
.toChars());
699 else if (v
.storage_class
& STC
.nodefaultctor
)
700 error(funcdecl
.loc
, "field `%s` must be initialized in constructor", v
.toChars());
701 else if (v
.type
.needsNested())
702 error(funcdecl
.loc
, "field `%s` must be initialized in constructor, because it is nested struct", v
.toChars());
706 bool mustInit
= (v
.storage_class
& STC
.nodefaultctor || v
.type
.needsNested());
707 if (mustInit
&& !(sc2
.ctorflow
.fieldinit
[i
].csx
& CSX
.this_ctor
))
709 .error(funcdecl
.loc
, "%s `%s` field `%s` must be initialized but skipped", funcdecl
.kind
, funcdecl
.toPrettyChars
, v
.toChars());
714 sc2
.ctorflow
.freeFieldinit();
716 if (cd
&& !(sc2
.ctorflow
.callSuper
& (CSX
.any_ctor | CSX
.halt
)) && cd
.baseClass
&& cd
.baseClass
.ctor
)
718 sc2
.ctorflow
.callSuper
= CSX
.none
;
720 // Insert implicit super() at start of fbody
721 Type tthis
= ad2
.type
.addMod(funcdecl
.vthis
.type
.mod
);
722 FuncDeclaration fd
= resolveFuncCall(Loc
.initial
, sc2
, cd
.baseClass
.ctor
, null, tthis
, ArgumentList(), FuncResolveFlag
.quiet
);
725 .error(funcdecl
.loc
, "%s `%s` no match for implicit `super()` call in constructor", funcdecl
.kind
, funcdecl
.toPrettyChars
);
727 else if (fd
.storage_class
& STC
.disable
)
729 .error(funcdecl
.loc
, "%s `%s` cannot call `super()` implicitly because it is annotated with `@disable`", funcdecl
.kind
, funcdecl
.toPrettyChars
);
733 Expression e1
= new SuperExp(Loc
.initial
);
734 Expression e
= new CallExp(Loc
.initial
, e1
);
735 e
= e
.expressionSemantic(sc2
);
736 Statement s
= new ExpStatement(Loc
.initial
, e
);
737 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, s
, funcdecl
.fbody
);
740 //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper);
743 /* https://issues.dlang.org/show_bug.cgi?id=17502
744 * Wait until after the return type has been inferred before
745 * generating the contracts for this function, and merging contracts
748 * https://issues.dlang.org/show_bug.cgi?id=17893
749 * However should take care to generate this before inferered
750 * function attributes are applied, such as 'nothrow'.
752 * This was originally at the end of the first semantic pass, but
753 * required a fix-up to be done here for the '__result' variable
754 * type of __ensure() inside auto functions, but this didn't work
755 * if the out parameter was implicit.
757 funcdecl
.buildEnsureRequire();
759 // Check for errors related to 'nothrow'.
760 const blockexit
= funcdecl
.fbody
.blockExit(funcdecl
, f
.isnothrow ? global
.errorSink
: null);
761 if (f
.isnothrow
&& blockexit
& BE
.throw_
)
762 error(funcdecl
.loc
, "%s `%s` may throw but is marked as `nothrow`", funcdecl
.kind(), funcdecl
.toPrettyChars());
764 if (!(blockexit
& (BE
.throw_ | BE
.halt
) || funcdecl
.hasCatches
))
766 /* Don't generate unwind tables for this function
767 * https://issues.dlang.org/show_bug.cgi?id=17997
769 funcdecl
.hasNoEH
= true;
772 if (funcdecl
.nothrowInprocess
)
774 if (funcdecl
.type
== f
)
775 f
= cast(TypeFunction
)f
.copy();
776 f
.isnothrow
= !(blockexit
& BE
.throw_
);
779 if (funcdecl
.fbody
.isErrorStatement())
782 else if (ad2
&& funcdecl
.isCtorDeclaration())
788 if (blockexit
& BE
.fallthru
)
790 Statement s
= new ReturnStatement(funcdecl
.loc
, null);
791 s
= s
.statementSemantic(sc2
);
792 funcdecl
.fbody
= new CompoundStatement(funcdecl
.loc
, funcdecl
.fbody
, s
);
793 funcdecl
.hasReturnExp |
= (funcdecl
.hasReturnExp
& 1 ?
16 : 1);
796 else if (funcdecl
.fes
)
798 // For foreach(){} body, append a return 0;
799 if (blockexit
& BE
.fallthru
)
801 Expression e
= IntegerExp
.literal
!0;
802 Statement s
= new ReturnStatement(Loc
.initial
, e
);
803 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, funcdecl
.fbody
, s
);
804 funcdecl
.hasReturnExp |
= (funcdecl
.hasReturnExp
& 1 ?
16 : 1);
806 assert(!funcdecl
.returnLabel
);
808 else if (f
.next
.toBasetype().ty
== Tnoreturn
)
810 // Fallthrough despite being declared as noreturn? return is already rejected when evaluating the ReturnStatement
811 if (blockexit
& BE
.fallthru
)
813 .error(funcdecl
.loc
, "%s `%s` is typed as `%s` but does return", funcdecl
.kind
, funcdecl
.toPrettyChars
, f
.next
.toChars());
814 funcdecl
.loc
.errorSupplemental("`noreturn` functions must either throw, abort or loop indefinitely");
819 const(bool) inlineAsm
= (funcdecl
.hasReturnExp
& 8) != 0;
820 if ((blockexit
& BE
.fallthru
) && f
.next
.ty
!= Tvoid
&& !inlineAsm
&& !(sc
.flags
& SCOPE
.Cfile
))
822 if (!funcdecl
.hasReturnExp
)
823 .error(funcdecl
.loc
, "%s `%s` has no `return` statement, but is expected to return a value of type `%s`", funcdecl
.kind
, funcdecl
.toPrettyChars
, f
.next
.toChars());
825 .error(funcdecl
.loc
, "%s `%s` no `return exp;` or `assert(0);` at end of function", funcdecl
.kind
, funcdecl
.toPrettyChars
);
829 if (funcdecl
.returns
)
831 bool implicit0
= addReturn0();
832 Type tret
= implicit0 ? Type
.tint32
: f
.next
;
833 assert(tret
.ty
!= Tvoid
);
834 if (funcdecl
.vresult || funcdecl
.returnLabel
)
835 funcdecl
.buildResultVar(scout ? scout
: sc2
, tret
);
837 /* Cannot move this loop into NrvoWalker, because
838 * returns[i] may be in the nested delegate for foreach-body.
840 for (size_t i
= 0; i
< funcdecl
.returns
.length
; i
++)
842 ReturnStatement rs
= (*funcdecl
.returns
)[i
];
843 Expression exp
= rs
.exp
;
844 if (exp
.op
== EXP
.error
)
846 if (tret
.ty
== Terror
)
848 // https://issues.dlang.org/show_bug.cgi?id=13702
849 exp
= checkGC(sc2
, exp
);
853 /* If the expression in the return statement (exp) cannot be implicitly
854 * converted to the return type (tret) of the function and if the
855 * type of the expression is type isolated, then it may be possible
856 * that a promotion to `immutable` or `inout` (through a cast) will
857 * match the return type.
859 if (!exp
.implicitConvTo(tret
) && funcdecl
.isTypeIsolated(exp
.type
))
861 /* https://issues.dlang.org/show_bug.cgi?id=20073
863 * The problem is that if the type of the returned expression (exp.type)
864 * is an aggregated declaration with an alias this, the alias this may be
865 * used for the conversion testing without it being an isolated type.
867 * To make sure this does not happen, we can test here the implicit conversion
868 * only for the aggregated declaration type by using `implicitConvToWithoutAliasThis`.
869 * The implicit conversion with alias this is taken care of later.
871 AggregateDeclaration aggDecl
= isAggregate(exp
.type
);
875 if (aggDecl
&& aggDecl
.aliasthis
)
878 tclass
= exp
.type
.isTypeClass();
880 tstruct
= exp
.type
.isTypeStruct();
881 assert(tclass || tstruct
);
887 if ((cast(TypeClass
)(exp
.type
.immutableOf())).implicitConvToWithoutAliasThis(tret
))
888 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
889 else if ((cast(TypeClass
)(exp
.type
.wildOf())).implicitConvToWithoutAliasThis(tret
))
890 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
894 if ((cast(TypeStruct
)exp
.type
.immutableOf()).implicitConvToWithoutAliasThis(tret
))
895 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
896 else if ((cast(TypeStruct
)exp
.type
.immutableOf()).implicitConvToWithoutAliasThis(tret
))
897 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
902 if (exp
.type
.immutableOf().implicitConvTo(tret
))
903 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
904 else if (exp
.type
.wildOf().implicitConvTo(tret
))
905 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
909 const hasCopyCtor
= exp
.type
.ty
== Tstruct
&& (cast(TypeStruct
)exp
.type
).sym
.hasCopyCtor
;
910 // if a copy constructor is present, the return type conversion will be handled by it
911 if (!(hasCopyCtor
&& exp
.isLvalue()))
913 if (f
.isref
&& !MODimplicitConv(exp
.type
.mod
, tret
.mod
) && !tret
.isTypeSArray())
914 error(exp
.loc
, "expression `%s` of type `%s` is not implicitly convertible to return type `ref %s`",
915 exp
.toChars(), exp
.type
.toChars(), tret
.toChars());
917 exp
= exp
.implicitCastTo(sc2
, tret
);
922 // Function returns a reference
923 exp
= exp
.toLvalue(sc2
, "`ref` return");
924 checkReturnEscapeRef(sc2
, exp
, false);
925 exp
= exp
.optimize(WANTvalue
, /*keepLvalue*/ true);
929 exp
= exp
.optimize(WANTvalue
);
931 /* https://issues.dlang.org/show_bug.cgi?id=10789
932 * If NRVO is not possible, all returned lvalues should call their postblits.
934 if (!funcdecl
.isNRVO())
935 exp
= doCopyOrMove(sc2
, exp
, f
.next
);
937 if (tret
.hasPointers())
938 checkReturnEscape(sc2
, exp
, false);
941 exp
= checkGC(sc2
, exp
);
943 if (funcdecl
.vresult
)
945 // Create: return vresult = exp;
946 exp
= new BlitExp(rs
.loc
, funcdecl
.vresult
, exp
);
947 exp
.type
= funcdecl
.vresult
.type
;
950 exp
= Expression
.combine(exp
, new IntegerExp(rs
.caseDim
));
952 else if (funcdecl
.tintro
&& !tret
.equals(funcdecl
.tintro
.nextOf()))
954 exp
= exp
.implicitCastTo(sc2
, funcdecl
.tintro
.nextOf());
959 if (funcdecl
.nrvo_var || funcdecl
.returnLabel
)
961 scope NrvoWalker nw
= new NrvoWalker();
964 nw
.visitStmt(funcdecl
.fbody
);
970 if (global
.params
.inclusiveInContracts
)
972 funcdecl
.frequire
= funcdecl
.mergeFrequireInclusivePreview(
973 funcdecl
.frequire
, funcdecl
.fdrequireParams
);
977 funcdecl
.frequire
= funcdecl
.mergeFrequire(funcdecl
.frequire
, funcdecl
.fdrequireParams
);
979 funcdecl
.fensure
= funcdecl
.mergeFensure(funcdecl
.fensure
, Id
.result
, funcdecl
.fdensureParams
);
981 Statement freq
= funcdecl
.frequire
;
982 Statement fens
= funcdecl
.fensure
;
984 /* Do the semantic analysis on the [in] preconditions and
985 * [out] postconditions.
987 immutable bool isnothrow
= f
.isnothrow
&& !funcdecl
.nothrowInprocess
;
990 /* frequire is composed of the [in] contracts
992 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
993 sym
.parent
= sc2
.scopesym
;
994 sym
.endlinnum
= funcdecl
.endloc
.linnum
;
996 sc2
.flags
= (sc2
.flags
& ~SCOPE
.contract
) | SCOPE
.require
;
998 // BUG: need to error if accessing out parameters
999 // BUG: need to disallow returns
1000 // BUG: verify that all in and ref parameters are read
1001 freq
= freq
.statementSemantic(sc2
);
1003 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1004 const blockExit
= freq
.blockExit(funcdecl
, null);
1005 if (blockExit
& BE
.throw_
)
1008 // @@@DEPRECATED_2.111@@@
1009 // Deprecated in 2.101, can be made an error in 2.111
1010 deprecation(funcdecl
.loc
, "`%s`: `in` contract may throw but function is marked as `nothrow`",
1011 funcdecl
.toPrettyChars());
1012 else if (funcdecl
.nothrowInprocess
)
1013 f
.isnothrow
= false;
1016 funcdecl
.hasNoEH
= false;
1020 if (global
.params
.useIn
== CHECKENABLE
.off
)
1026 /* fensure is composed of the [out] contracts
1028 if (f
.next
.ty
== Tvoid
&& funcdecl
.fensures
)
1030 foreach (e
; *funcdecl
.fensures
)
1034 .error(e
.ensure
.loc
, "%s `%s` `void` functions have no result", funcdecl
.kind
, funcdecl
.toPrettyChars
);
1041 sc2
.flags
= (sc2
.flags
& ~SCOPE
.contract
) | SCOPE
.ensure
;
1043 // BUG: need to disallow returns and throws
1045 if (funcdecl
.fensure
&& f
.next
.ty
!= Tvoid
)
1046 funcdecl
.buildResultVar(scout
, f
.next
);
1048 fens
= fens
.statementSemantic(sc2
);
1050 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1051 const blockExit
= fens
.blockExit(funcdecl
, null);
1052 if (blockExit
& BE
.throw_
)
1055 // @@@DEPRECATED_2.111@@@
1056 // Deprecated in 2.101, can be made an error in 2.111
1057 deprecation(funcdecl
.loc
, "`%s`: `out` contract may throw but function is marked as `nothrow`",
1058 funcdecl
.toPrettyChars());
1059 else if (funcdecl
.nothrowInprocess
)
1060 f
.isnothrow
= false;
1063 funcdecl
.hasNoEH
= false;
1067 if (global
.params
.useOut
== CHECKENABLE
.off
)
1070 if (funcdecl
.fbody
&& funcdecl
.fbody
.isErrorStatement())
1075 auto a
= new Statements();
1076 // Merge in initialization of 'out' parameters
1077 if (funcdecl
.parameters
)
1079 for (size_t i
= 0; i
< funcdecl
.parameters
.length
; i
++)
1081 VarDeclaration v
= (*funcdecl
.parameters
)[i
];
1082 if (v
.storage_class
& STC
.out_
)
1086 .error(v
.loc
, "%s `%s` zero-length `out` parameters are not allowed.", v
.kind
, v
.toPrettyChars
);
1089 ExpInitializer ie
= v
._init
.isExpInitializer();
1091 if (auto iec
= ie
.exp
.isConstructExp())
1093 // construction occurred in parameter processing
1094 auto ec
= new AssignExp(iec
.loc
, iec
.e1
, iec
.e2
);
1098 a
.push(new ExpStatement(Loc
.initial
, ie
.exp
));
1105 /* Advance to elements[] member of TypeInfo_Tuple with:
1106 * _arguments = v_arguments.elements;
1108 Expression e
= new VarExp(Loc
.initial
, funcdecl
.v_arguments
);
1109 e
= new DotIdExp(Loc
.initial
, e
, Id
.elements
);
1110 e
= new ConstructExp(Loc
.initial
, _arguments
, e
);
1111 e
= e
.expressionSemantic(sc2
);
1113 _arguments
._init
= new ExpInitializer(Loc
.initial
, e
);
1114 auto de = new DeclarationExp(Loc
.initial
, _arguments
);
1115 a
.push(new ExpStatement(Loc
.initial
, de));
1118 // Merge contracts together with body into one compound statement
1120 if (freq || fpreinv
)
1125 freq
= new CompoundStatement(Loc
.initial
, freq
, fpreinv
);
1131 a
.push(funcdecl
.fbody
);
1133 if (fens || fpostinv
)
1138 fens
= new CompoundStatement(Loc
.initial
, fpostinv
, fens
);
1140 auto ls
= new LabelStatement(Loc
.initial
, Id
.returnLabel
, fens
);
1141 funcdecl
.returnLabel
.statement
= ls
;
1142 a
.push(funcdecl
.returnLabel
.statement
);
1144 if (f
.next
.ty
!= Tvoid
&& funcdecl
.vresult
)
1146 // Create: return vresult;
1147 Expression e
= new VarExp(Loc
.initial
, funcdecl
.vresult
);
1148 if (funcdecl
.tintro
)
1150 e
= e
.implicitCastTo(sc
, funcdecl
.tintro
.nextOf());
1151 e
= e
.expressionSemantic(sc
);
1153 auto s
= new ReturnStatement(Loc
.initial
, e
);
1159 // Add a return 0; statement
1160 Statement s
= new ReturnStatement(Loc
.initial
, IntegerExp
.literal
!0);
1164 Statement sbody
= new CompoundStatement(Loc
.initial
, a
);
1166 /* Append destructor calls for parameters as finally blocks.
1168 if (funcdecl
.parameters
)
1170 // check if callee destroys arguments
1171 const bool paramsNeedDtor
= target
.isCalleeDestroyingArgs(f
);
1173 foreach (v
; *funcdecl
.parameters
)
1175 if (v
.isReference() ||
(v
.storage_class
& STC
.lazy_
))
1177 if (v
.needsScopeDtor())
1179 v
.storage_class |
= STC
.nodtor
;
1180 if (!paramsNeedDtor
)
1183 // same with ExpStatement.scopeCode()
1184 Statement s
= new DtorExpStatement(Loc
.initial
, v
.edtor
, v
);
1186 s
= s
.statementSemantic(sc2
);
1188 const blockexit
= s
.blockExit(funcdecl
, isnothrow ? global
.errorSink
: null);
1189 if (blockexit
& BE
.throw_
)
1191 funcdecl
.hasNoEH
= false;
1193 error(funcdecl
.loc
, "%s `%s` may throw but is marked as `nothrow`", funcdecl
.kind(), funcdecl
.toPrettyChars());
1194 else if (funcdecl
.nothrowInprocess
)
1195 f
.isnothrow
= false;
1198 if (sbody
.blockExit(funcdecl
, f
.isnothrow ? global
.errorSink
: null) == BE
.fallthru
)
1199 sbody
= new CompoundStatement(Loc
.initial
, sbody
, s
);
1201 sbody
= new TryFinallyStatement(Loc
.initial
, sbody
, s
);
1205 // from this point on all possible 'throwers' are checked
1206 funcdecl
.nothrowInprocess
= false;
1208 if (funcdecl
.isSynchronized())
1210 /* Wrap the entire function body in a synchronized statement
1212 ClassDeclaration cd
= funcdecl
.toParentDecl().isClassDeclaration();
1215 if (target
.libraryObjectMonitors(funcdecl
, sbody
))
1218 if (funcdecl
.isStatic())
1220 // The monitor is in the ClassInfo
1221 vsync
= new DotIdExp(funcdecl
.loc
, symbolToExp(cd
, funcdecl
.loc
, sc2
, false), Id
.classinfo
);
1225 // 'this' is the monitor
1226 vsync
= new VarExp(funcdecl
.loc
, funcdecl
.vthis
);
1227 if (funcdecl
.hasDualContext())
1229 vsync
= new PtrExp(funcdecl
.loc
, vsync
);
1230 vsync
= new IndexExp(funcdecl
.loc
, vsync
, IntegerExp
.literal
!0);
1233 sbody
= new PeelStatement(sbody
); // don't redo semantic()
1234 sbody
= new SynchronizedStatement(funcdecl
.loc
, vsync
, sbody
);
1235 sbody
= sbody
.statementSemantic(sc2
);
1240 .error(funcdecl
.loc
, "%s `%s` synchronized function `%s` must be a member of a class", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars());
1244 // If declaration has no body, don't set sbody to prevent incorrect codegen.
1245 if (funcdecl
.fbody || funcdecl
.allowsContractWithoutBody())
1246 funcdecl
.fbody
= sbody
;
1249 // Check for undefined labels
1250 if (funcdecl
.labtab
)
1251 foreach (keyValue
; funcdecl
.labtab
.tab
.asRange
)
1253 //printf(" KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
1254 LabelDsymbol label
= cast(LabelDsymbol
)keyValue
.value
;
1255 if (!label
.statement
&& (!label
.deleted || label
.iasm
))
1257 .error(label
.loc
, "%s `%s` label `%s` is undefined", funcdecl
.kind
, funcdecl
.toPrettyChars
, label
.toChars());
1261 // Fix up forward-referenced gotos
1262 if (funcdecl
.gotos
&& !funcdecl
.isCsymbol())
1264 for (size_t i
= 0; i
< funcdecl
.gotos
.length
; ++i
)
1266 (*funcdecl
.gotos
)[i
].checkLabel();
1270 if (funcdecl
.isNaked() && (funcdecl
.fensures || funcdecl
.frequires
))
1271 .error(funcdecl
.loc
, "%s `%s` naked assembly functions with contracts are not supported", funcdecl
.kind
, funcdecl
.toPrettyChars
);
1273 sc2
.ctorflow
.callSuper
= CSX
.none
;
1277 if (funcdecl
.checkClosure())
1279 // We should be setting errors here instead of relying on the global error count.
1283 /* If function survived being marked as impure, then it is pure
1285 if (funcdecl
.purityInprocess
)
1287 funcdecl
.purityInprocess
= false;
1288 if (funcdecl
.type
== f
)
1289 f
= cast(TypeFunction
)f
.copy();
1290 f
.purity
= PURE
.fwdref
;
1293 if (funcdecl
.safetyInprocess
)
1295 funcdecl
.safetyInprocess
= false;
1296 if (funcdecl
.type
== f
)
1297 f
= cast(TypeFunction
)f
.copy();
1298 f
.trust
= TRUST
.safe
;
1301 if (funcdecl
.nogcInprocess
)
1303 funcdecl
.nogcInprocess
= false;
1304 if (funcdecl
.type
== f
)
1305 f
= cast(TypeFunction
)f
.copy();
1309 finishScopeParamInference(funcdecl
, f
);
1311 // reset deco to apply inference result to mangled name
1312 if (f
!= funcdecl
.type
)
1315 // Do semantic type AFTER pure/nothrow inference.
1316 if (!f
.deco
&& funcdecl
.ident
!= Id
.xopEquals
&& funcdecl
.ident
!= Id
.xopCmp
)
1319 if (funcdecl
.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
1322 sc
.linkage
= funcdecl
._linkage
; // https://issues.dlang.org/show_bug.cgi?id=8496
1323 funcdecl
.type
= f
.typeSemantic(funcdecl
.loc
, sc
);
1327 // Check `extern(C++)` functions for invalid the return/parameter types
1328 if (funcdecl
._linkage
== LINK
.cpp
)
1330 static bool isCppNonMappableType(Type type
, Parameter param
= null, Type origType
= null)
1332 // Don't allow D `immutable` and `shared` types to be interfaced with C++
1333 if (type
.isImmutable() || type
.isShared())
1335 else if (Type cpptype
= target
.cpp
.parameterType(type
))
1338 if (origType
is null)
1341 // Permit types that are handled by toCppMangle. This list should be kept in sync with
1342 // each visit method in dmd.cppmangle and dmd.cppmanglewin.
1359 if (!origType
.isTypePointer())
1364 if (!type
.isTypeBasic())
1369 // Descend to the enclosing type
1370 if (auto tnext
= type
.nextOf())
1371 return isCppNonMappableType(tnext
, param
, origType
);
1375 if (isCppNonMappableType(f
.next
.toBasetype()))
1377 .error(funcdecl
.loc
, "%s `%s` cannot return type `%s` because its linkage is `extern(C++)`", funcdecl
.kind
, funcdecl
.toPrettyChars
, f
.next
.toChars());
1378 if (f
.next
.isTypeDArray())
1379 errorSupplemental(funcdecl
.loc
, "slices are specific to D and do not have a counterpart representation in C++", f
.next
.toChars());
1380 funcdecl
.errors
= true;
1382 foreach (i
, param
; f
.parameterList
)
1384 if (isCppNonMappableType(param
.type
.toBasetype(), param
))
1386 .error(funcdecl
.loc
, "%s `%s` cannot have parameter of type `%s` because its linkage is `extern(C++)`", funcdecl
.kind
, funcdecl
.toPrettyChars
, param
.type
.toChars());
1387 if (param
.type
.toBasetype().isTypeSArray())
1388 errorSupplemental(funcdecl
.loc
, "perhaps use a `%s*` type instead",
1389 param
.type
.nextOf().mutableOf().unSharedOf().toChars());
1390 funcdecl
.errors
= true;
1396 if (global
.params
.useDIP1021
&& funcdecl
.fbody
&& funcdecl
.type
.ty
!= Terror
&&
1397 funcdecl
.type
.isTypeFunction().islive
)
1402 /* If this function had instantiated with gagging, error reproduction will be
1403 * done by TemplateInstance::semantic.
1404 * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
1406 funcdecl
.semanticRun
= PASS
.semantic3done
;
1407 if ((global
.errors
!= oldErrors
) ||
(funcdecl
.fbody
&& funcdecl
.fbody
.isErrorStatement()))
1408 funcdecl
.hasSemantic3Errors
= true;
1410 funcdecl
.hasSemantic3Errors
= false;
1411 if (funcdecl
.type
.ty
== Terror
)
1412 funcdecl
.errors
= true;
1413 //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars());
1417 override void visit(CtorDeclaration ctor
)
1419 //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars());
1420 if (ctor
.semanticRun
>= PASS
.semantic3
)
1423 /* If any of the fields of the aggregate have a destructor, add
1424 * scope (failure) { this.fieldDtor(); }
1425 * as the first statement of the constructor (unless the constructor
1426 * doesn't define a body - @disable, extern)
1427 *.It is not necessary to add it after
1428 * each initialization of a field, because destruction of .init constructed
1429 * structs should be benign.
1430 * https://issues.dlang.org/show_bug.cgi?id=14246
1432 AggregateDeclaration ad
= ctor
.isMemberDecl();
1433 if (!ctor
.fbody ||
!ad ||
!ad
.fieldDtor ||
1434 global
.params
.dtorFields
== FeatureState
.disabled ||
!global
.params
.useExceptions || ctor
.type
.toTypeFunction
.isnothrow
)
1435 return visit(cast(FuncDeclaration
)ctor
);
1440 Expression e
= new ThisExp(ctor
.loc
);
1441 e
.type
= ad
.type
.mutableOf();
1442 e
= new DotVarExp(ctor
.loc
, e
, ad
.fieldDtor
, false);
1443 auto ce
= new CallExp(ctor
.loc
, e
);
1444 auto sexp
= new ExpStatement(ctor
.loc
, ce
);
1445 auto ss
= new ScopeStatement(ctor
.loc
, sexp
, ctor
.loc
);
1447 // @@@DEPRECATED_2.106@@@
1448 // Allow negligible attribute violations to allow for a smooth
1449 // transition. Remove this after the usual deprecation period
1451 if (global
.params
.dtorFields
== FeatureState
.default_
)
1453 auto ctf
= cast(TypeFunction
) ctor
.type
;
1454 auto dtf
= cast(TypeFunction
) ad
.fieldDtor
.type
;
1456 const ngErr
= ctf
.isnogc
&& !dtf
.isnogc
;
1457 const puErr
= ctf
.purity
&& !dtf
.purity
;
1458 const saErr
= ctf
.trust
== TRUST
.safe
&& dtf
.trust
<= TRUST
.system
;
1460 if (ngErr || puErr || saErr
)
1462 // storage_class is apparently not set for dtor & ctor
1465 (ngErr ? STC
.nogc
: 0) |
1466 (puErr ? STC
.pure_
: 0) |
1467 (saErr ? STC
.system
: 0)
1469 ctor
.loc
.deprecation("`%s` has stricter attributes than its destructor (`%s`)", ctor
.toPrettyChars(), ob
.peekChars());
1470 ctor
.loc
.deprecationSupplemental("The destructor will be called if an exception is thrown");
1471 ctor
.loc
.deprecationSupplemental("Either make the constructor `nothrow` or adjust the field destructors");
1473 ce
.ignoreAttributes
= true;
1480 * try { ctor.fbody; }
1481 * catch (Exception __o)
1482 * { this.fieldDtor(); throw __o; }
1483 * This differs from the alternate scope(failure) version in that an Exception
1484 * is caught rather than a Throwable. This enables the optimization whereby
1485 * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only
1486 * applies to Exception.)
1488 Identifier id
= Identifier
.generateId("__o");
1489 auto ts
= new ThrowStatement(ctor
.loc
, new IdentifierExp(ctor
.loc
, id
));
1490 auto handler
= new CompoundStatement(ctor
.loc
, ss
, ts
);
1492 auto catches
= new Catches();
1493 auto ctch
= new Catch(ctor
.loc
, getException(), id
, handler
);
1496 ctor
.fbody
= new TryCatchStatement(ctor
.loc
, ctor
.fbody
, catches
);
1501 * scope (failure) { this.fieldDtor(); }
1502 * Hopefully we can use this version someday when scope(failure) catches
1503 * Exception instead of Throwable.
1505 auto s
= new ScopeGuardStatement(ctor
.loc
, TOK
.onScopeFailure
, ss
);
1506 ctor
.fbody
= new CompoundStatement(ctor
.loc
, s
, ctor
.fbody
);
1508 visit(cast(FuncDeclaration
)ctor
);
1512 override void visit(Nspace ns
)
1514 if (ns
.semanticRun
>= PASS
.semantic3
)
1516 ns
.semanticRun
= PASS
.semantic3
;
1519 printf("Nspace::semantic3('%s')\n", ns
.toChars());
1525 sc
.linkage
= LINK
.cpp
;
1526 foreach (s
; *ns
.members
)
1533 override void visit(AttribDeclaration ad
)
1535 Dsymbols
* d
= ad
.include(sc
);
1539 Scope
* sc2
= ad
.newScope(sc
);
1540 for (size_t i
= 0; i
< d
.length
; i
++)
1542 Dsymbol s
= (*d
)[i
];
1549 override void visit(AggregateDeclaration ad
)
1551 //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors);
1555 StructDeclaration sd
= ad
.isStructDeclaration();
1556 if (!sc
) // from runDeferredSemantic3 for TypeInfo generation
1559 sd
.semanticTypeInfoMembers();
1563 auto sc2
= ad
.newScope(sc
);
1565 for (size_t i
= 0; i
< ad
.members
.length
; i
++)
1567 Dsymbol s
= (*ad
.members
)[i
];
1573 // Instantiate RTInfo!S to provide a pointer bitmap for the GC
1574 // Don't do it in -betterC or on unused deprecated / error types
1575 if (!ad
.getRTInfo
&& global
.params
.useTypeInfo
&& Type
.rtinfo
&&
1576 (!ad
.isDeprecated() || global
.params
.useDeprecated
!= DiagnosticReporting
.error
) &&
1577 (ad
.type
&& ad
.type
.ty
!= Terror
))
1579 // Evaluate: RTinfo!type
1580 auto tiargs
= new Objects();
1581 tiargs
.push(ad
.type
);
1582 auto ti
= new TemplateInstance(ad
.loc
, Type
.rtinfo
, tiargs
);
1584 Scope
* sc3
= ti
.tempdecl
._scope
.startCTFE();
1585 sc3
.tinst
= sc
.tinst
;
1586 sc3
.minst
= sc
.minst
;
1587 if (ad
.isDeprecated())
1588 sc3
.stc |
= STC
.deprecated_
;
1590 ti
.dsymbolSemantic(sc3
);
1593 auto e
= symbolToExp(ti
.toAlias(), Loc
.initial
, sc3
, false);
1597 e
= e
.ctfeInterpret();
1601 sd
.semanticTypeInfoMembers();
1602 ad
.semanticRun
= PASS
.semantic3done
;
1606 private struct FuncDeclSem3
1608 // The FuncDeclaration subject to Semantic analysis
1609 FuncDeclaration funcdecl
;
1611 // Scope of analysis
1613 this(FuncDeclaration fd
,Scope
* s
) scope @safe
1619 /* Checks that the overridden functions (if any) have in contracts if
1620 * funcdecl has an in contract.
1622 void checkInContractOverrides()
1624 if (funcdecl
.frequires
)
1626 for (size_t i
= 0; i
< funcdecl
.foverrides
.length
; i
++)
1628 FuncDeclaration fdv
= funcdecl
.foverrides
[i
];
1629 if (fdv
.fbody
&& !fdv
.frequires
)
1631 .error(funcdecl
.loc
, "%s `%s` cannot have an in contract when overridden function `%s` does not have an in contract", funcdecl
.kind
, funcdecl
.toPrettyChars
, fdv
.toPrettyChars());
1639 extern (C
++) void semanticTypeInfoMembers(StructDeclaration sd
)
1643 sd
.xeq
.semanticRun
< PASS
.semantic3done
)
1645 uint errors
= global
.startGagging();
1646 sd
.xeq
.semantic3(sd
.xeq
._scope
);
1647 if (global
.endGagging(errors
))
1653 sd
.xcmp
.semanticRun
< PASS
.semantic3done
)
1655 uint errors
= global
.startGagging();
1656 sd
.xcmp
.semantic3(sd
.xcmp
._scope
);
1657 if (global
.endGagging(errors
))
1658 sd
.xcmp
= sd
.xerrcmp
;
1661 FuncDeclaration ftostr
= search_toString(sd
);
1664 ftostr
.semanticRun
< PASS
.semantic3done
)
1666 ftostr
.semantic3(ftostr
._scope
);
1671 sd
.xhash
.semanticRun
< PASS
.semantic3done
)
1673 sd
.xhash
.semantic3(sd
.xhash
._scope
);
1677 sd
.postblit
._scope
&&
1678 sd
.postblit
.semanticRun
< PASS
.semantic3done
)
1680 sd
.postblit
.semantic3(sd
.postblit
._scope
);
1685 sd
.dtor
.semanticRun
< PASS
.semantic3done
)
1687 sd
.dtor
.semantic3(sd
.dtor
._scope
);