2 * Performs the semantic3 stage, which deals with function bodies.
4 * Copyright: Copyright (C) 1999-2023 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
;
46 import dmd
.identifier
;
59 import dmd
.root
.filename
;
60 import dmd
.common
.outbuffer
;
62 import dmd
.rootobject
;
64 import dmd
.sideeffect
;
65 import dmd
.statementsem
;
66 import dmd
.staticassert
;
71 import dmd
.templateparamsem
;
78 /*************************************
79 * Does semantic analysis on function bodies.
81 extern(C
++) void semantic3(Dsymbol dsym
, Scope
* sc
)
83 scope v
= new Semantic3Visitor(sc
);
87 private extern(C
++) final class Semantic3Visitor
: Visitor
89 alias visit
= Visitor
.visit
;
92 this(Scope
* sc
) scope @safe
97 override void visit(Dsymbol
) {}
99 override void visit(TemplateInstance tempinst
)
103 printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", tempinst
.toChars(), tempinst
.semanticRun
);
105 //if (toChars()[0] == 'D') *(char*)0=0;
106 if (tempinst
.semanticRun
>= PASS
.semantic3
)
108 tempinst
.semanticRun
= PASS
.semantic3
;
109 if (tempinst
.errors ||
!tempinst
.members
)
112 TemplateDeclaration tempdecl
= tempinst
.tempdecl
.isTemplateDeclaration();
115 sc
= tempdecl
._scope
;
116 sc
= sc
.push(tempinst
.argsym
);
117 sc
= sc
.push(tempinst
);
119 sc
.minst
= tempinst
.minst
;
121 int needGagging
= (tempinst
.gagged
&& !global
.gag
);
122 uint olderrors
= global
.errors
;
123 int oldGaggedErrors
= -1; // dead-store to prevent spurious warning
124 /* If this is a gagged instantiation, gag errors.
125 * Future optimisation: If the results are actually needed, errors
126 * would already be gagged, so we don't really need to run semantic
130 oldGaggedErrors
= global
.startGagging();
132 for (size_t i
= 0; i
< tempinst
.members
.length
; i
++)
134 Dsymbol s
= (*tempinst
.members
)[i
];
136 if (tempinst
.gagged
&& global
.errors
!= olderrors
)
140 if (global
.errors
!= olderrors
)
142 if (!tempinst
.errors
)
144 if (!tempdecl
.literal
)
145 .error(tempinst
.loc
, "%s `%s` error instantiating", tempinst
.kind
, tempinst
.toPrettyChars
);
147 tempinst
.tinst
.printInstantiationTrace();
149 tempinst
.errors
= true;
152 global
.endGagging(oldGaggedErrors
);
158 override void visit(TemplateMixin tmix
)
160 if (tmix
.semanticRun
>= PASS
.semantic3
)
162 tmix
.semanticRun
= PASS
.semantic3
;
165 printf("TemplateMixin.semantic3('%s')\n", tmix
.toChars());
170 sc
= sc
.push(tmix
.argsym
);
173 uint olderrors
= global
.errors
;
175 for (size_t i
= 0; i
< tmix
.members
.length
; i
++)
177 Dsymbol s
= (*tmix
.members
)[i
];
181 if (global
.errors
!= olderrors
)
182 errorSupplemental(tmix
.loc
, "parent scope from here: `mixin %s`", tmix
.toChars());
188 override void visit(Module mod
)
190 //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
191 if (mod
.semanticRun
!= PASS
.semantic2done
)
193 mod
.semanticRun
= PASS
.semantic3
;
194 // Note that modules get their own scope, from scratch.
195 // This is so regardless of where in the syntax a module
196 // gets imported, it is unaffected by context.
197 Scope
* sc
= Scope
.createGlobal(mod
, global
.errorSink
); // create root scope
198 //printf("Module = %p\n", sc.scopesym);
201 // Pass 3 semantic routines: do initializers and function bodies
202 for (size_t i
= 0; i
< mod
.members
.length
; i
++)
204 Dsymbol s
= (*mod
.members
)[i
];
205 //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
208 mod
.runDeferredSemantic2();
211 if (mod
.userAttribDecl
)
213 mod
.userAttribDecl
.semantic3(sc
);
217 mod
.semanticRun
= PASS
.semantic3done
;
220 override void visit(FuncDeclaration funcdecl
)
222 //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", funcdecl.kind(), funcdecl.toChars(), sc);
223 /* Determine if function should add `return 0;`
227 //printf("addReturn0()\n");
228 auto f
= funcdecl
.type
.isTypeFunction();
231 if (sc
.flags
& SCOPE
.Cfile
&& funcdecl
.isCMain() && f
.next
.ty
== Tint32
)
234 return f
.next
.ty
== Tvoid
&&
235 (funcdecl
.isMain() || global
.params
.betterC
&& 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
.userAttribDecl
= null;
350 if (sc2
.intypeof
== 1)
352 sc2
.ctorflow
.fieldinit
= null;
354 /* Note: When a lambda is defined immediately under aggregate member
355 * scope, it should be contextless due to prevent interior pointers.
357 * // dg points 'this' - its interior pointer
358 * class C { int x; void delegate() dg = (){ this.x = 1; }; }
360 * However, lambdas could be used inside typeof, in order to check
361 * some expressions validity at compile time. For such case the lambda
362 * body can access aggregate instance members.
364 * class C { int x; static assert(is(typeof({ this.x = 1; }))); }
366 * To properly accept it, mark these lambdas as member functions.
368 if (auto fld = funcdecl
.isFuncLiteralDeclaration())
370 if (auto ad
= funcdecl
.isMember2())
374 if (fld.tok
== TOK
.delegate_
)
375 .error(funcdecl
.loc
, "%s `%s` cannot be %s members", funcdecl
.kind
, funcdecl
.toPrettyChars
, ad
.kind());
377 fld.tok
= TOK
.function_
;
381 if (fld.tok
!= TOK
.function_
)
382 fld.tok
= TOK
.delegate_
;
387 funcdecl
.declareThis(sc2
);
389 // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710
390 // No compiler supports this, and there was never any spec for it.
391 // @@@DEPRECATED_2.116@@@
392 // Deprecated in 2.096, can be made an error in 2.116.
393 // The deprecation period is longer than usual as dual-context
394 // functions may be widely used by dmd-compiled projects.
395 // It also gives more time for the implementation of dual-context
396 // functions to be reworked as a frontend-only feature.
397 if (funcdecl
.hasDualContext())
399 .deprecation(funcdecl
.loc
, "%s `%s` function requires a dual-context, which is deprecated", funcdecl
.kind
, funcdecl
.toPrettyChars
);
400 if (auto ti
= sc2
.parent ? sc2
.parent
.isInstantiated() : null)
401 ti
.printInstantiationTrace(Classification
.deprecation
);
404 //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis);
405 //if (vthis) printf("\tvthis.type = %s\n", vthis.type.toChars());
407 // Declare hidden variable _arguments[] and _argptr
408 if (f
.parameterList
.varargs
== VarArg
.variadic
)
410 if (f
.linkage
== LINK
.d
)
412 // Variadic arguments depend on Typeinfo being defined.
413 if (!global
.params
.useTypeInfo ||
!Type
.dtypeinfo ||
!Type
.typeinfotypelist
)
415 if (!global
.params
.useTypeInfo
)
418 .error(funcdecl
.loc
, "%s `%s` D-style variadic functions cannot be used with `-fno-rtti`", funcdecl
.kind
, funcdecl
.toPrettyChars
);
420 .error(funcdecl
.loc
, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl
.kind
, funcdecl
.toPrettyChars
);
422 else if (!Type
.typeinfotypelist
)
423 .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
);
425 .error(funcdecl
.loc
, "%s `%s` `object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions", funcdecl
.kind
, funcdecl
.toPrettyChars
);
429 // Declare _arguments[]
430 funcdecl
.v_arguments
= new VarDeclaration(funcdecl
.loc
, Type
.typeinfotypelist
.type
, Id
._arguments_typeinfo
, null);
431 funcdecl
.v_arguments
.storage_class |
= STC
.temp | STC
.parameter
;
432 funcdecl
.v_arguments
.dsymbolSemantic(sc2
);
433 sc2
.insert(funcdecl
.v_arguments
);
434 funcdecl
.v_arguments
.parent
= funcdecl
;
436 //Type t = Type.dtypeinfo.type.constOf().arrayOf();
437 Type t
= Type
.dtypeinfo
.type
.arrayOf();
438 _arguments
= new VarDeclaration(funcdecl
.loc
, t
, Id
._arguments
, null);
439 _arguments
.storage_class |
= STC
.temp
;
440 _arguments
.dsymbolSemantic(sc2
);
441 sc2
.insert(_arguments
);
442 _arguments
.parent
= funcdecl
;
444 if (f
.linkage
== LINK
.d || f
.parameterList
.length
)
447 Type t
= target
.va_listType(funcdecl
.loc
, sc
);
448 // Init is handled in FuncDeclaration_toObjFile
449 funcdecl
.v_argptr
= new VarDeclaration(funcdecl
.loc
, t
, Id
._argptr
, new VoidInitializer(funcdecl
.loc
));
450 funcdecl
.v_argptr
.storage_class |
= STC
.temp
;
451 funcdecl
.v_argptr
.dsymbolSemantic(sc2
);
452 sc2
.insert(funcdecl
.v_argptr
);
453 funcdecl
.v_argptr
.parent
= funcdecl
;
457 /* Declare all the function parameters as variables
458 * and install them in parameters[]
460 if (const nparams
= f
.parameterList
.length
)
462 /* parameters[] has all the tuples removed, as the back end
463 * doesn't know about tuples
465 funcdecl
.parameters
= new VarDeclarations();
466 funcdecl
.parameters
.reserve(nparams
);
467 foreach (i
, fparam
; f
.parameterList
)
469 Identifier id
= fparam
.ident
;
470 StorageClass
stc = 0;
473 /* Generate identifier for un-named parameter,
474 * because we need it later on.
476 fparam
.ident
= id
= Identifier
.generateId("__param_", i
);
479 Type vtype
= fparam
.type
;
480 auto v
= new VarDeclaration(fparam
.loc
, vtype
, id
, null);
481 //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars());
482 stc |
= STC
.parameter
;
483 if (f
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
)
488 stc |
= fparam
.storageClass
& (STC
.IOR | STC
.return_ | STC
.scope_ | STC
.lazy_ | STC
.final_ | STC
.TYPECTOR | STC
.nodtor | STC
.returnScope | STC
.register
);
489 v
.storage_class
= stc;
490 v
.dsymbolSemantic(sc2
);
493 .error(funcdecl
.loc
, "%s `%s` parameter `%s.%s` is already defined", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars(), v
.toChars());
494 funcdecl
.errors
= true;
497 funcdecl
.parameters
.push(v
);
498 funcdecl
.localsymtab
.insert(v
);
500 if (fparam
.userAttribDecl
)
501 v
.userAttribDecl
= fparam
.userAttribDecl
;
505 // Declare the tuple symbols and put them in the symbol table,
506 // but not in parameters[].
507 if (f
.parameterList
.parameters
)
508 foreach (fparam
; *f
.parameterList
.parameters
)
511 continue; // never used, so ignore
513 if (fparam
.type
.ty
!= Ttuple
)
516 TypeTuple t
= cast(TypeTuple
)fparam
.type
;
517 size_t dim
= Parameter
.dim(t
.arguments
);
518 auto exps
= new Objects(dim
);
519 foreach (j
; 0 .. dim
)
521 Parameter narg
= Parameter
.getNth(t
.arguments
, j
);
523 VarDeclaration v
= sc2
.search(Loc
.initial
, narg
.ident
, null).isVarDeclaration();
525 (*exps
)[j
] = new VarExp(v
.loc
, v
);
527 assert(fparam
.ident
);
528 auto v
= new TupleDeclaration(funcdecl
.loc
, fparam
.ident
, exps
);
529 //printf("declaring tuple %s\n", v.toChars());
532 .error(funcdecl
.loc
, "%s `%s` parameter `%s.%s` is already defined", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars(), v
.toChars());
533 funcdecl
.localsymtab
.insert(v
);
537 // Precondition invariant
538 Statement fpreinv
= null;
539 if (funcdecl
.addPreInvariant())
541 Expression e
= addInvariant(funcdecl
.isThis(), funcdecl
.vthis
);
543 fpreinv
= new ExpStatement(Loc
.initial
, e
);
546 // Postcondition invariant
547 Statement fpostinv
= null;
548 if (funcdecl
.addPostInvariant())
550 Expression e
= addInvariant(funcdecl
.isThis(), funcdecl
.vthis
);
552 fpostinv
= new ExpStatement(Loc
.initial
, e
);
555 // Pre/Postcondition contract
557 funcdecl
.buildEnsureRequire();
560 if (needEnsure || funcdecl
.addPostInvariant())
562 /* https://issues.dlang.org/show_bug.cgi?id=3657
563 * Set the correct end line number for fensure scope.
565 uint fensure_endlin
= funcdecl
.endloc
.linnum
;
566 if (funcdecl
.fensure
)
567 if (auto s
= funcdecl
.fensure
.isScopeStatement())
568 fensure_endlin
= s
.endloc
.linnum
;
570 if ((needEnsure
&& global
.params
.useOut
== CHECKENABLE
.on
) || fpostinv
)
572 funcdecl
.returnLabel
= funcdecl
.searchLabel(Id
.returnLabel
);
575 // scope of out contract (need for vresult.semantic)
576 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
577 sym
.parent
= sc2
.scopesym
;
578 sym
.endlinnum
= fensure_endlin
;
579 scout
= sc2
.push(sym
);
584 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
585 sym
.parent
= sc2
.scopesym
;
586 sym
.endlinnum
= funcdecl
.endloc
.linnum
;
589 auto ad2
= funcdecl
.isMemberLocal();
591 /* If this is a class constructor
593 if (ad2
&& funcdecl
.isCtorDeclaration())
595 sc2
.ctorflow
.allocFieldinit(ad2
.fields
.length
);
596 foreach (v
; ad2
.fields
)
602 bool inferRef
= (f
.isref
&& (funcdecl
.storage_class
& STC
.auto_
));
604 funcdecl
.fbody
= funcdecl
.fbody
.statementSemantic(sc2
);
606 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, new Statements());
608 if (funcdecl
.isNaked())
610 fpreinv
= null; // can't accommodate with no stack frame
614 assert(funcdecl
.type
== f ||
(funcdecl
.type
.ty
== Tfunction
&& f
.purity
== PURE
.impure
&& (cast(TypeFunction
)funcdecl
.type
).purity
>= PURE
.fwdref
));
615 f
= cast(TypeFunction
)funcdecl
.type
;
617 if (funcdecl
.inferRetType
)
619 // If no return type inferred yet, then infer a void
622 if (f
.checkRetType(funcdecl
.loc
))
623 funcdecl
.fbody
= new ErrorStatement();
625 funcdecl
.checkMain(); // Check main() parameters and return type
629 f
.next
.checkComplexTransition(funcdecl
.loc
, sc
);
631 if (funcdecl
.returns
&& !funcdecl
.fbody
.isErrorStatement())
633 for (size_t i
= 0; i
< funcdecl
.returns
.length
;)
635 Expression exp
= (*funcdecl
.returns
)[i
].exp
;
636 if (exp
.op
== EXP
.variable
&& (cast(VarExp
)exp
).var
== funcdecl
.vresult
)
639 exp
.type
= Type
.tint32
;
642 // Remove `return vresult;` from returns
643 funcdecl
.returns
.remove(i
);
646 if (inferRef
&& f
.isref
&& !exp
.type
.constConv(f
.next
)) // https://issues.dlang.org/show_bug.cgi?id=13336
651 if (f
.isref
) // Function returns a reference
653 if (funcdecl
.storage_class
& STC
.auto_
)
654 funcdecl
.storage_class
&= ~STC
.auto_
;
658 if (!target
.isReturnOnStack(f
, funcdecl
.needThis()) ||
!funcdecl
.checkNRVO())
659 funcdecl
.isNRVO
= false;
661 if (funcdecl
.fbody
.isErrorStatement())
664 else if (funcdecl
.isStaticCtorDeclaration())
666 /* It's a static constructor. Ensure that all
667 * ctor consts were initialized.
669 ScopeDsymbol pd
= funcdecl
.toParent().isScopeDsymbol();
670 for (size_t i
= 0; i
< pd
.members
.length
; i
++)
672 Dsymbol s
= (*pd
.members
)[i
];
673 s
.checkCtorConstInit();
676 else if (ad2
&& funcdecl
.isCtorDeclaration())
678 ClassDeclaration cd
= ad2
.isClassDeclaration();
680 // Verify that all the ctorinit fields got initialized
681 if (!(sc2
.ctorflow
.callSuper
& CSX
.this_ctor
))
683 foreach (i
, v
; ad2
.fields
)
685 if (v
.isThisDeclaration())
689 /* Current bugs in the flow analysis:
690 * 1. union members should not produce error messages even if
692 * 2. structs should recognize delegating opAssign calls as well
693 * as delegating calls to other constructors
695 if (v
.isCtorinit() && !v
.type
.isMutable() && cd
)
696 .error(funcdecl
.loc
, "%s `%s` missing initializer for %s field `%s`", funcdecl
.kind
, funcdecl
.toPrettyChars
, MODtoChars(v
.type
.mod
), v
.toChars());
697 else if (v
.storage_class
& STC
.nodefaultctor
)
698 error(funcdecl
.loc
, "field `%s` must be initialized in constructor", v
.toChars());
699 else if (v
.type
.needsNested())
700 error(funcdecl
.loc
, "field `%s` must be initialized in constructor, because it is nested struct", v
.toChars());
704 bool mustInit
= (v
.storage_class
& STC
.nodefaultctor || v
.type
.needsNested());
705 if (mustInit
&& !(sc2
.ctorflow
.fieldinit
[i
].csx
& CSX
.this_ctor
))
707 .error(funcdecl
.loc
, "%s `%s` field `%s` must be initialized but skipped", funcdecl
.kind
, funcdecl
.toPrettyChars
, v
.toChars());
712 sc2
.ctorflow
.freeFieldinit();
714 if (cd
&& !(sc2
.ctorflow
.callSuper
& (CSX
.any_ctor | CSX
.halt
)) && cd
.baseClass
&& cd
.baseClass
.ctor
)
716 sc2
.ctorflow
.callSuper
= CSX
.none
;
718 // Insert implicit super() at start of fbody
719 Type tthis
= ad2
.type
.addMod(funcdecl
.vthis
.type
.mod
);
720 FuncDeclaration fd
= resolveFuncCall(Loc
.initial
, sc2
, cd
.baseClass
.ctor
, null, tthis
, ArgumentList(), FuncResolveFlag
.quiet
);
723 .error(funcdecl
.loc
, "%s `%s` no match for implicit `super()` call in constructor", funcdecl
.kind
, funcdecl
.toPrettyChars
);
725 else if (fd
.storage_class
& STC
.disable
)
727 .error(funcdecl
.loc
, "%s `%s` cannot call `super()` implicitly because it is annotated with `@disable`", funcdecl
.kind
, funcdecl
.toPrettyChars
);
731 Expression e1
= new SuperExp(Loc
.initial
);
732 Expression e
= new CallExp(Loc
.initial
, e1
);
733 e
= e
.expressionSemantic(sc2
);
734 Statement s
= new ExpStatement(Loc
.initial
, e
);
735 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, s
, funcdecl
.fbody
);
738 //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper);
741 /* https://issues.dlang.org/show_bug.cgi?id=17502
742 * Wait until after the return type has been inferred before
743 * generating the contracts for this function, and merging contracts
746 * https://issues.dlang.org/show_bug.cgi?id=17893
747 * However should take care to generate this before inferered
748 * function attributes are applied, such as 'nothrow'.
750 * This was originally at the end of the first semantic pass, but
751 * required a fix-up to be done here for the '__result' variable
752 * type of __ensure() inside auto functions, but this didn't work
753 * if the out parameter was implicit.
755 funcdecl
.buildEnsureRequire();
757 // Check for errors related to 'nothrow'.
758 const blockexit
= funcdecl
.fbody
.blockExit(funcdecl
, f
.isnothrow ? global
.errorSink
: null);
759 if (f
.isnothrow
&& blockexit
& BE
.throw_
)
760 error(funcdecl
.loc
, "%s `%s` may throw but is marked as `nothrow`", funcdecl
.kind(), funcdecl
.toPrettyChars());
762 if (!(blockexit
& (BE
.throw_ | BE
.halt
) || funcdecl
.hasCatches
))
764 /* Don't generate unwind tables for this function
765 * https://issues.dlang.org/show_bug.cgi?id=17997
767 funcdecl
.hasNoEH
= true;
770 if (funcdecl
.nothrowInprocess
)
772 if (funcdecl
.type
== f
)
773 f
= cast(TypeFunction
)f
.copy();
774 f
.isnothrow
= !(blockexit
& BE
.throw_
);
777 if (funcdecl
.fbody
.isErrorStatement())
780 else if (ad2
&& funcdecl
.isCtorDeclaration())
786 if (blockexit
& BE
.fallthru
)
788 Statement s
= new ReturnStatement(funcdecl
.loc
, null);
789 s
= s
.statementSemantic(sc2
);
790 funcdecl
.fbody
= new CompoundStatement(funcdecl
.loc
, funcdecl
.fbody
, s
);
791 funcdecl
.hasReturnExp |
= (funcdecl
.hasReturnExp
& 1 ?
16 : 1);
794 else if (funcdecl
.fes
)
796 // For foreach(){} body, append a return 0;
797 if (blockexit
& BE
.fallthru
)
799 Expression e
= IntegerExp
.literal
!0;
800 Statement s
= new ReturnStatement(Loc
.initial
, e
);
801 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, funcdecl
.fbody
, s
);
802 funcdecl
.hasReturnExp |
= (funcdecl
.hasReturnExp
& 1 ?
16 : 1);
804 assert(!funcdecl
.returnLabel
);
806 else if (f
.next
.toBasetype().ty
== Tnoreturn
)
808 // Fallthrough despite being declared as noreturn? return is already rejected when evaluating the ReturnStatement
809 if (blockexit
& BE
.fallthru
)
811 .error(funcdecl
.loc
, "%s `%s` is typed as `%s` but does return", funcdecl
.kind
, funcdecl
.toPrettyChars
, f
.next
.toChars());
812 funcdecl
.loc
.errorSupplemental("`noreturn` functions must either throw, abort or loop indefinitely");
817 const(bool) inlineAsm
= (funcdecl
.hasReturnExp
& 8) != 0;
818 if ((blockexit
& BE
.fallthru
) && f
.next
.ty
!= Tvoid
&& !inlineAsm
&& !(sc
.flags
& SCOPE
.Cfile
))
820 if (!funcdecl
.hasReturnExp
)
821 .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());
823 .error(funcdecl
.loc
, "%s `%s` no `return exp;` or `assert(0);` at end of function", funcdecl
.kind
, funcdecl
.toPrettyChars
);
827 if (funcdecl
.returns
)
829 bool implicit0
= addReturn0();
830 Type tret
= implicit0 ? Type
.tint32
: f
.next
;
831 assert(tret
.ty
!= Tvoid
);
832 if (funcdecl
.vresult || funcdecl
.returnLabel
)
833 funcdecl
.buildResultVar(scout ? scout
: sc2
, tret
);
835 /* Cannot move this loop into NrvoWalker, because
836 * returns[i] may be in the nested delegate for foreach-body.
838 for (size_t i
= 0; i
< funcdecl
.returns
.length
; i
++)
840 ReturnStatement rs
= (*funcdecl
.returns
)[i
];
841 Expression exp
= rs
.exp
;
842 if (exp
.op
== EXP
.error
)
844 if (tret
.ty
== Terror
)
846 // https://issues.dlang.org/show_bug.cgi?id=13702
847 exp
= checkGC(sc2
, exp
);
851 /* If the expression in the return statement (exp) cannot be implicitly
852 * converted to the return type (tret) of the function and if the
853 * type of the expression is type isolated, then it may be possible
854 * that a promotion to `immutable` or `inout` (through a cast) will
855 * match the return type.
857 if (!exp
.implicitConvTo(tret
) && funcdecl
.isTypeIsolated(exp
.type
))
859 /* https://issues.dlang.org/show_bug.cgi?id=20073
861 * The problem is that if the type of the returned expression (exp.type)
862 * is an aggregated declaration with an alias this, the alias this may be
863 * used for the conversion testing without it being an isolated type.
865 * To make sure this does not happen, we can test here the implicit conversion
866 * only for the aggregated declaration type by using `implicitConvToWithoutAliasThis`.
867 * The implicit conversion with alias this is taken care of later.
869 AggregateDeclaration aggDecl
= isAggregate(exp
.type
);
873 if (aggDecl
&& aggDecl
.aliasthis
)
876 tclass
= exp
.type
.isTypeClass();
878 tstruct
= exp
.type
.isTypeStruct();
879 assert(tclass || tstruct
);
885 if ((cast(TypeClass
)(exp
.type
.immutableOf())).implicitConvToWithoutAliasThis(tret
))
886 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
887 else if ((cast(TypeClass
)(exp
.type
.wildOf())).implicitConvToWithoutAliasThis(tret
))
888 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
892 if ((cast(TypeStruct
)exp
.type
.immutableOf()).implicitConvToWithoutAliasThis(tret
))
893 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
894 else if ((cast(TypeStruct
)exp
.type
.immutableOf()).implicitConvToWithoutAliasThis(tret
))
895 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
900 if (exp
.type
.immutableOf().implicitConvTo(tret
))
901 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
902 else if (exp
.type
.wildOf().implicitConvTo(tret
))
903 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
907 const hasCopyCtor
= exp
.type
.ty
== Tstruct
&& (cast(TypeStruct
)exp
.type
).sym
.hasCopyCtor
;
908 // if a copy constructor is present, the return type conversion will be handled by it
909 if (!(hasCopyCtor
&& exp
.isLvalue()))
911 if (f
.isref
&& !MODimplicitConv(exp
.type
.mod
, tret
.mod
) && !tret
.isTypeSArray())
912 error(exp
.loc
, "expression `%s` of type `%s` is not implicitly convertible to return type `ref %s`",
913 exp
.toChars(), exp
.type
.toChars(), tret
.toChars());
915 exp
= exp
.implicitCastTo(sc2
, tret
);
920 // Function returns a reference
921 exp
= exp
.toLvalue(sc2
, "`ref` return");
922 checkReturnEscapeRef(sc2
, exp
, false);
923 exp
= exp
.optimize(WANTvalue
, /*keepLvalue*/ true);
927 exp
= exp
.optimize(WANTvalue
);
929 /* https://issues.dlang.org/show_bug.cgi?id=10789
930 * If NRVO is not possible, all returned lvalues should call their postblits.
932 if (!funcdecl
.isNRVO())
933 exp
= doCopyOrMove(sc2
, exp
, f
.next
);
935 if (tret
.hasPointers())
936 checkReturnEscape(sc2
, exp
, false);
939 exp
= checkGC(sc2
, exp
);
941 if (funcdecl
.vresult
)
943 // Create: return vresult = exp;
944 exp
= new BlitExp(rs
.loc
, funcdecl
.vresult
, exp
);
945 exp
.type
= funcdecl
.vresult
.type
;
948 exp
= Expression
.combine(exp
, new IntegerExp(rs
.caseDim
));
950 else if (funcdecl
.tintro
&& !tret
.equals(funcdecl
.tintro
.nextOf()))
952 exp
= exp
.implicitCastTo(sc2
, funcdecl
.tintro
.nextOf());
957 if (funcdecl
.nrvo_var || funcdecl
.returnLabel
)
959 scope NrvoWalker nw
= new NrvoWalker();
962 nw
.visitStmt(funcdecl
.fbody
);
968 if (global
.params
.inclusiveInContracts
)
970 funcdecl
.frequire
= funcdecl
.mergeFrequireInclusivePreview(
971 funcdecl
.frequire
, funcdecl
.fdrequireParams
);
975 funcdecl
.frequire
= funcdecl
.mergeFrequire(funcdecl
.frequire
, funcdecl
.fdrequireParams
);
977 funcdecl
.fensure
= funcdecl
.mergeFensure(funcdecl
.fensure
, Id
.result
, funcdecl
.fdensureParams
);
979 Statement freq
= funcdecl
.frequire
;
980 Statement fens
= funcdecl
.fensure
;
982 /* Do the semantic analysis on the [in] preconditions and
983 * [out] postconditions.
985 immutable bool isnothrow
= f
.isnothrow
&& !funcdecl
.nothrowInprocess
;
988 /* frequire is composed of the [in] contracts
990 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
991 sym
.parent
= sc2
.scopesym
;
992 sym
.endlinnum
= funcdecl
.endloc
.linnum
;
994 sc2
.flags
= (sc2
.flags
& ~SCOPE
.contract
) | SCOPE
.require
;
996 // BUG: need to error if accessing out parameters
997 // BUG: need to disallow returns
998 // BUG: verify that all in and ref parameters are read
999 freq
= freq
.statementSemantic(sc2
);
1001 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1002 const blockExit
= freq
.blockExit(funcdecl
, null);
1003 if (blockExit
& BE
.throw_
)
1006 // @@@DEPRECATED_2.111@@@
1007 // Deprecated in 2.101, can be made an error in 2.111
1008 deprecation(funcdecl
.loc
, "`%s`: `in` contract may throw but function is marked as `nothrow`",
1009 funcdecl
.toPrettyChars());
1010 else if (funcdecl
.nothrowInprocess
)
1011 f
.isnothrow
= false;
1014 funcdecl
.hasNoEH
= false;
1018 if (global
.params
.useIn
== CHECKENABLE
.off
)
1024 /* fensure is composed of the [out] contracts
1026 if (f
.next
.ty
== Tvoid
&& funcdecl
.fensures
)
1028 foreach (e
; *funcdecl
.fensures
)
1032 .error(e
.ensure
.loc
, "%s `%s` `void` functions have no result", funcdecl
.kind
, funcdecl
.toPrettyChars
);
1039 sc2
.flags
= (sc2
.flags
& ~SCOPE
.contract
) | SCOPE
.ensure
;
1041 // BUG: need to disallow returns and throws
1043 if (funcdecl
.fensure
&& f
.next
.ty
!= Tvoid
)
1044 funcdecl
.buildResultVar(scout
, f
.next
);
1046 fens
= fens
.statementSemantic(sc2
);
1048 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1049 const blockExit
= fens
.blockExit(funcdecl
, null);
1050 if (blockExit
& BE
.throw_
)
1053 // @@@DEPRECATED_2.111@@@
1054 // Deprecated in 2.101, can be made an error in 2.111
1055 deprecation(funcdecl
.loc
, "`%s`: `out` contract may throw but function is marked as `nothrow`",
1056 funcdecl
.toPrettyChars());
1057 else if (funcdecl
.nothrowInprocess
)
1058 f
.isnothrow
= false;
1061 funcdecl
.hasNoEH
= false;
1065 if (global
.params
.useOut
== CHECKENABLE
.off
)
1068 if (funcdecl
.fbody
&& funcdecl
.fbody
.isErrorStatement())
1073 auto a
= new Statements();
1074 // Merge in initialization of 'out' parameters
1075 if (funcdecl
.parameters
)
1077 for (size_t i
= 0; i
< funcdecl
.parameters
.length
; i
++)
1079 VarDeclaration v
= (*funcdecl
.parameters
)[i
];
1080 if (v
.storage_class
& STC
.out_
)
1084 .error(v
.loc
, "%s `%s` zero-length `out` parameters are not allowed.", v
.kind
, v
.toPrettyChars
);
1087 ExpInitializer ie
= v
._init
.isExpInitializer();
1089 if (auto iec
= ie
.exp
.isConstructExp())
1091 // construction occurred in parameter processing
1092 auto ec
= new AssignExp(iec
.loc
, iec
.e1
, iec
.e2
);
1096 a
.push(new ExpStatement(Loc
.initial
, ie
.exp
));
1103 /* Advance to elements[] member of TypeInfo_Tuple with:
1104 * _arguments = v_arguments.elements;
1106 Expression e
= new VarExp(Loc
.initial
, funcdecl
.v_arguments
);
1107 e
= new DotIdExp(Loc
.initial
, e
, Id
.elements
);
1108 e
= new ConstructExp(Loc
.initial
, _arguments
, e
);
1109 e
= e
.expressionSemantic(sc2
);
1111 _arguments
._init
= new ExpInitializer(Loc
.initial
, e
);
1112 auto de = new DeclarationExp(Loc
.initial
, _arguments
);
1113 a
.push(new ExpStatement(Loc
.initial
, de));
1116 // Merge contracts together with body into one compound statement
1118 if (freq || fpreinv
)
1123 freq
= new CompoundStatement(Loc
.initial
, freq
, fpreinv
);
1129 a
.push(funcdecl
.fbody
);
1131 if (fens || fpostinv
)
1136 fens
= new CompoundStatement(Loc
.initial
, fpostinv
, fens
);
1138 auto ls
= new LabelStatement(Loc
.initial
, Id
.returnLabel
, fens
);
1139 funcdecl
.returnLabel
.statement
= ls
;
1140 a
.push(funcdecl
.returnLabel
.statement
);
1142 if (f
.next
.ty
!= Tvoid
&& funcdecl
.vresult
)
1144 // Create: return vresult;
1145 Expression e
= new VarExp(Loc
.initial
, funcdecl
.vresult
);
1146 if (funcdecl
.tintro
)
1148 e
= e
.implicitCastTo(sc
, funcdecl
.tintro
.nextOf());
1149 e
= e
.expressionSemantic(sc
);
1151 auto s
= new ReturnStatement(Loc
.initial
, e
);
1157 // Add a return 0; statement
1158 Statement s
= new ReturnStatement(Loc
.initial
, IntegerExp
.literal
!0);
1162 Statement sbody
= new CompoundStatement(Loc
.initial
, a
);
1164 /* Append destructor calls for parameters as finally blocks.
1166 if (funcdecl
.parameters
)
1168 // check if callee destroys arguments
1169 const bool paramsNeedDtor
= target
.isCalleeDestroyingArgs(f
);
1171 foreach (v
; *funcdecl
.parameters
)
1173 if (v
.isReference() ||
(v
.storage_class
& STC
.lazy_
))
1175 if (v
.needsScopeDtor())
1177 v
.storage_class |
= STC
.nodtor
;
1178 if (!paramsNeedDtor
)
1181 // same with ExpStatement.scopeCode()
1182 Statement s
= new DtorExpStatement(Loc
.initial
, v
.edtor
, v
);
1184 s
= s
.statementSemantic(sc2
);
1186 const blockexit
= s
.blockExit(funcdecl
, isnothrow ? global
.errorSink
: null);
1187 if (blockexit
& BE
.throw_
)
1189 funcdecl
.hasNoEH
= false;
1191 error(funcdecl
.loc
, "%s `%s` may throw but is marked as `nothrow`", funcdecl
.kind(), funcdecl
.toPrettyChars());
1192 else if (funcdecl
.nothrowInprocess
)
1193 f
.isnothrow
= false;
1196 if (sbody
.blockExit(funcdecl
, f
.isnothrow ? global
.errorSink
: null) == BE
.fallthru
)
1197 sbody
= new CompoundStatement(Loc
.initial
, sbody
, s
);
1199 sbody
= new TryFinallyStatement(Loc
.initial
, sbody
, s
);
1203 // from this point on all possible 'throwers' are checked
1204 funcdecl
.nothrowInprocess
= false;
1206 if (funcdecl
.isSynchronized())
1208 /* Wrap the entire function body in a synchronized statement
1210 ClassDeclaration cd
= funcdecl
.toParentDecl().isClassDeclaration();
1213 if (target
.libraryObjectMonitors(funcdecl
, sbody
))
1216 if (funcdecl
.isStatic())
1218 // The monitor is in the ClassInfo
1219 vsync
= new DotIdExp(funcdecl
.loc
, symbolToExp(cd
, funcdecl
.loc
, sc2
, false), Id
.classinfo
);
1223 // 'this' is the monitor
1224 vsync
= new VarExp(funcdecl
.loc
, funcdecl
.vthis
);
1225 if (funcdecl
.hasDualContext())
1227 vsync
= new PtrExp(funcdecl
.loc
, vsync
);
1228 vsync
= new IndexExp(funcdecl
.loc
, vsync
, IntegerExp
.literal
!0);
1231 sbody
= new PeelStatement(sbody
); // don't redo semantic()
1232 sbody
= new SynchronizedStatement(funcdecl
.loc
, vsync
, sbody
);
1233 sbody
= sbody
.statementSemantic(sc2
);
1238 .error(funcdecl
.loc
, "%s `%s` synchronized function `%s` must be a member of a class", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars());
1242 // If declaration has no body, don't set sbody to prevent incorrect codegen.
1243 if (funcdecl
.fbody || funcdecl
.allowsContractWithoutBody())
1244 funcdecl
.fbody
= sbody
;
1247 // Check for undefined labels
1248 if (funcdecl
.labtab
)
1249 foreach (keyValue
; funcdecl
.labtab
.tab
.asRange
)
1251 //printf(" KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
1252 LabelDsymbol label
= cast(LabelDsymbol
)keyValue
.value
;
1253 if (!label
.statement
&& (!label
.deleted || label
.iasm
))
1255 .error(label
.loc
, "%s `%s` label `%s` is undefined", funcdecl
.kind
, funcdecl
.toPrettyChars
, label
.toChars());
1259 // Fix up forward-referenced gotos
1260 if (funcdecl
.gotos
&& !funcdecl
.isCsymbol())
1262 for (size_t i
= 0; i
< funcdecl
.gotos
.length
; ++i
)
1264 (*funcdecl
.gotos
)[i
].checkLabel();
1268 if (funcdecl
.isNaked() && (funcdecl
.fensures || funcdecl
.frequires
))
1269 .error(funcdecl
.loc
, "%s `%s` naked assembly functions with contracts are not supported", funcdecl
.kind
, funcdecl
.toPrettyChars
);
1271 sc2
.ctorflow
.callSuper
= CSX
.none
;
1275 if (funcdecl
.checkClosure())
1277 // We should be setting errors here instead of relying on the global error count.
1281 /* If function survived being marked as impure, then it is pure
1283 if (funcdecl
.purityInprocess
)
1285 funcdecl
.purityInprocess
= false;
1286 if (funcdecl
.type
== f
)
1287 f
= cast(TypeFunction
)f
.copy();
1288 f
.purity
= PURE
.fwdref
;
1291 if (funcdecl
.safetyInprocess
)
1293 funcdecl
.safetyInprocess
= false;
1294 if (funcdecl
.type
== f
)
1295 f
= cast(TypeFunction
)f
.copy();
1296 f
.trust
= TRUST
.safe
;
1299 if (funcdecl
.nogcInprocess
)
1301 funcdecl
.nogcInprocess
= false;
1302 if (funcdecl
.type
== f
)
1303 f
= cast(TypeFunction
)f
.copy();
1307 finishScopeParamInference(funcdecl
, f
);
1309 // reset deco to apply inference result to mangled name
1310 if (f
!= funcdecl
.type
)
1313 // Do semantic type AFTER pure/nothrow inference.
1314 if (!f
.deco
&& funcdecl
.ident
!= Id
.xopEquals
&& funcdecl
.ident
!= Id
.xopCmp
)
1317 if (funcdecl
.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
1320 sc
.linkage
= funcdecl
._linkage
; // https://issues.dlang.org/show_bug.cgi?id=8496
1321 funcdecl
.type
= f
.typeSemantic(funcdecl
.loc
, sc
);
1325 // Check `extern(C++)` functions for invalid the return/parameter types
1326 if (funcdecl
._linkage
== LINK
.cpp
)
1328 static bool isCppNonMappableType(Type type
, Parameter param
= null, Type origType
= null)
1330 // Don't allow D `immutable` and `shared` types to be interfaced with C++
1331 if (type
.isImmutable() || type
.isShared())
1333 else if (Type cpptype
= target
.cpp
.parameterType(type
))
1336 if (origType
is null)
1339 // Permit types that are handled by toCppMangle. This list should be kept in sync with
1340 // each visit method in dmd.cppmangle and dmd.cppmanglewin.
1357 if (!origType
.isTypePointer())
1362 if (!type
.isTypeBasic())
1367 // Descend to the enclosing type
1368 if (auto tnext
= type
.nextOf())
1369 return isCppNonMappableType(tnext
, param
, origType
);
1373 if (isCppNonMappableType(f
.next
.toBasetype()))
1375 .error(funcdecl
.loc
, "%s `%s` cannot return type `%s` because its linkage is `extern(C++)`", funcdecl
.kind
, funcdecl
.toPrettyChars
, f
.next
.toChars());
1376 if (f
.next
.isTypeDArray())
1377 errorSupplemental(funcdecl
.loc
, "slices are specific to D and do not have a counterpart representation in C++", f
.next
.toChars());
1378 funcdecl
.errors
= true;
1380 foreach (i
, param
; f
.parameterList
)
1382 if (isCppNonMappableType(param
.type
.toBasetype(), param
))
1384 .error(funcdecl
.loc
, "%s `%s` cannot have parameter of type `%s` because its linkage is `extern(C++)`", funcdecl
.kind
, funcdecl
.toPrettyChars
, param
.type
.toChars());
1385 if (param
.type
.toBasetype().isTypeSArray())
1386 errorSupplemental(funcdecl
.loc
, "perhaps use a `%s*` type instead",
1387 param
.type
.nextOf().mutableOf().unSharedOf().toChars());
1388 funcdecl
.errors
= true;
1394 if (global
.params
.useDIP1021
&& funcdecl
.fbody
&& funcdecl
.type
.ty
!= Terror
&&
1395 funcdecl
.type
.isTypeFunction().islive
)
1400 /* If this function had instantiated with gagging, error reproduction will be
1401 * done by TemplateInstance::semantic.
1402 * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
1404 funcdecl
.semanticRun
= PASS
.semantic3done
;
1405 if ((global
.errors
!= oldErrors
) ||
(funcdecl
.fbody
&& funcdecl
.fbody
.isErrorStatement()))
1406 funcdecl
.hasSemantic3Errors
= true;
1408 funcdecl
.hasSemantic3Errors
= false;
1409 if (funcdecl
.type
.ty
== Terror
)
1410 funcdecl
.errors
= true;
1411 //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars());
1415 override void visit(CtorDeclaration ctor
)
1417 //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars());
1418 if (ctor
.semanticRun
>= PASS
.semantic3
)
1421 /* If any of the fields of the aggregate have a destructor, add
1422 * scope (failure) { this.fieldDtor(); }
1423 * as the first statement of the constructor (unless the constructor
1424 * doesn't define a body - @disable, extern)
1425 *.It is not necessary to add it after
1426 * each initialization of a field, because destruction of .init constructed
1427 * structs should be benign.
1428 * https://issues.dlang.org/show_bug.cgi?id=14246
1430 AggregateDeclaration ad
= ctor
.isMemberDecl();
1431 if (!ctor
.fbody ||
!ad ||
!ad
.fieldDtor ||
1432 global
.params
.dtorFields
== FeatureState
.disabled ||
!global
.params
.useExceptions || ctor
.type
.toTypeFunction
.isnothrow
)
1433 return visit(cast(FuncDeclaration
)ctor
);
1438 Expression e
= new ThisExp(ctor
.loc
);
1439 e
.type
= ad
.type
.mutableOf();
1440 e
= new DotVarExp(ctor
.loc
, e
, ad
.fieldDtor
, false);
1441 auto ce
= new CallExp(ctor
.loc
, e
);
1442 auto sexp
= new ExpStatement(ctor
.loc
, ce
);
1443 auto ss
= new ScopeStatement(ctor
.loc
, sexp
, ctor
.loc
);
1445 // @@@DEPRECATED_2.106@@@
1446 // Allow negligible attribute violations to allow for a smooth
1447 // transition. Remove this after the usual deprecation period
1449 if (global
.params
.dtorFields
== FeatureState
.default_
)
1451 auto ctf
= cast(TypeFunction
) ctor
.type
;
1452 auto dtf
= cast(TypeFunction
) ad
.fieldDtor
.type
;
1454 const ngErr
= ctf
.isnogc
&& !dtf
.isnogc
;
1455 const puErr
= ctf
.purity
&& !dtf
.purity
;
1456 const saErr
= ctf
.trust
== TRUST
.safe
&& dtf
.trust
<= TRUST
.system
;
1458 if (ngErr || puErr || saErr
)
1460 // storage_class is apparently not set for dtor & ctor
1463 (ngErr ? STC
.nogc
: 0) |
1464 (puErr ? STC
.pure_
: 0) |
1465 (saErr ? STC
.system
: 0)
1467 ctor
.loc
.deprecation("`%s` has stricter attributes than its destructor (`%s`)", ctor
.toPrettyChars(), ob
.peekChars());
1468 ctor
.loc
.deprecationSupplemental("The destructor will be called if an exception is thrown");
1469 ctor
.loc
.deprecationSupplemental("Either make the constructor `nothrow` or adjust the field destructors");
1471 ce
.ignoreAttributes
= true;
1478 * try { ctor.fbody; }
1479 * catch (Exception __o)
1480 * { this.fieldDtor(); throw __o; }
1481 * This differs from the alternate scope(failure) version in that an Exception
1482 * is caught rather than a Throwable. This enables the optimization whereby
1483 * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only
1484 * applies to Exception.)
1486 Identifier id
= Identifier
.generateId("__o");
1487 auto ts
= new ThrowStatement(ctor
.loc
, new IdentifierExp(ctor
.loc
, id
));
1488 auto handler
= new CompoundStatement(ctor
.loc
, ss
, ts
);
1490 auto catches
= new Catches();
1491 auto ctch
= new Catch(ctor
.loc
, getException(), id
, handler
);
1494 ctor
.fbody
= new TryCatchStatement(ctor
.loc
, ctor
.fbody
, catches
);
1499 * scope (failure) { this.fieldDtor(); }
1500 * Hopefully we can use this version someday when scope(failure) catches
1501 * Exception instead of Throwable.
1503 auto s
= new ScopeGuardStatement(ctor
.loc
, TOK
.onScopeFailure
, ss
);
1504 ctor
.fbody
= new CompoundStatement(ctor
.loc
, s
, ctor
.fbody
);
1506 visit(cast(FuncDeclaration
)ctor
);
1510 override void visit(Nspace ns
)
1512 if (ns
.semanticRun
>= PASS
.semantic3
)
1514 ns
.semanticRun
= PASS
.semantic3
;
1517 printf("Nspace::semantic3('%s')\n", ns
.toChars());
1523 sc
.linkage
= LINK
.cpp
;
1524 foreach (s
; *ns
.members
)
1531 override void visit(AttribDeclaration ad
)
1533 Dsymbols
* d
= ad
.include(sc
);
1537 Scope
* sc2
= ad
.newScope(sc
);
1538 for (size_t i
= 0; i
< d
.length
; i
++)
1540 Dsymbol s
= (*d
)[i
];
1547 override void visit(AggregateDeclaration ad
)
1549 //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors);
1553 StructDeclaration sd
= ad
.isStructDeclaration();
1554 if (!sc
) // from runDeferredSemantic3 for TypeInfo generation
1557 sd
.semanticTypeInfoMembers();
1561 auto sc2
= ad
.newScope(sc
);
1563 for (size_t i
= 0; i
< ad
.members
.length
; i
++)
1565 Dsymbol s
= (*ad
.members
)[i
];
1571 // Instantiate RTInfo!S to provide a pointer bitmap for the GC
1572 // Don't do it in -betterC or on unused deprecated / error types
1573 if (!ad
.getRTInfo
&& global
.params
.useTypeInfo
&& Type
.rtinfo
&&
1574 (!ad
.isDeprecated() || global
.params
.useDeprecated
!= DiagnosticReporting
.error
) &&
1575 (ad
.type
&& ad
.type
.ty
!= Terror
))
1577 // Evaluate: RTinfo!type
1578 auto tiargs
= new Objects();
1579 tiargs
.push(ad
.type
);
1580 auto ti
= new TemplateInstance(ad
.loc
, Type
.rtinfo
, tiargs
);
1582 Scope
* sc3
= ti
.tempdecl
._scope
.startCTFE();
1583 sc3
.tinst
= sc
.tinst
;
1584 sc3
.minst
= sc
.minst
;
1585 if (ad
.isDeprecated())
1586 sc3
.stc |
= STC
.deprecated_
;
1588 ti
.dsymbolSemantic(sc3
);
1591 auto e
= symbolToExp(ti
.toAlias(), Loc
.initial
, sc3
, false);
1595 e
= e
.ctfeInterpret();
1599 sd
.semanticTypeInfoMembers();
1600 ad
.semanticRun
= PASS
.semantic3done
;
1604 private struct FuncDeclSem3
1606 // The FuncDeclaration subject to Semantic analysis
1607 FuncDeclaration funcdecl
;
1609 // Scope of analysis
1611 this(FuncDeclaration fd
,Scope
* s
) scope @safe
1617 /* Checks that the overridden functions (if any) have in contracts if
1618 * funcdecl has an in contract.
1620 void checkInContractOverrides()
1622 if (funcdecl
.frequires
)
1624 for (size_t i
= 0; i
< funcdecl
.foverrides
.length
; i
++)
1626 FuncDeclaration fdv
= funcdecl
.foverrides
[i
];
1627 if (fdv
.fbody
&& !fdv
.frequires
)
1629 .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());
1637 extern (C
++) void semanticTypeInfoMembers(StructDeclaration sd
)
1641 sd
.xeq
.semanticRun
< PASS
.semantic3done
)
1643 uint errors
= global
.startGagging();
1644 sd
.xeq
.semantic3(sd
.xeq
._scope
);
1645 if (global
.endGagging(errors
))
1651 sd
.xcmp
.semanticRun
< PASS
.semantic3done
)
1653 uint errors
= global
.startGagging();
1654 sd
.xcmp
.semantic3(sd
.xcmp
._scope
);
1655 if (global
.endGagging(errors
))
1656 sd
.xcmp
= sd
.xerrcmp
;
1659 FuncDeclaration ftostr
= search_toString(sd
);
1662 ftostr
.semanticRun
< PASS
.semantic3done
)
1664 ftostr
.semantic3(ftostr
._scope
);
1669 sd
.xhash
.semanticRun
< PASS
.semantic3done
)
1671 sd
.xhash
.semantic3(sd
.xhash
._scope
);
1675 sd
.postblit
._scope
&&
1676 sd
.postblit
.semanticRun
< PASS
.semantic3done
)
1678 sd
.postblit
.semantic3(sd
.postblit
._scope
);
1683 sd
.dtor
.semanticRun
< PASS
.semantic3done
)
1685 sd
.dtor
.semantic3(sd
.dtor
._scope
);