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
;
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
);
524 VarDeclaration v
= sc2
.search(Loc
.initial
, narg
.ident
, pscopesym
).isVarDeclaration();
526 (*exps
)[j
] = new VarExp(v
.loc
, v
);
528 assert(fparam
.ident
);
529 auto v
= new TupleDeclaration(funcdecl
.loc
, fparam
.ident
, exps
);
530 //printf("declaring tuple %s\n", v.toChars());
533 .error(funcdecl
.loc
, "%s `%s` parameter `%s.%s` is already defined", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars(), v
.toChars());
534 funcdecl
.localsymtab
.insert(v
);
538 // Precondition invariant
539 Statement fpreinv
= null;
540 if (funcdecl
.addPreInvariant())
542 Expression e
= addInvariant(funcdecl
.isThis(), funcdecl
.vthis
);
544 fpreinv
= new ExpStatement(Loc
.initial
, e
);
547 // Postcondition invariant
548 Statement fpostinv
= null;
549 if (funcdecl
.addPostInvariant())
551 Expression e
= addInvariant(funcdecl
.isThis(), funcdecl
.vthis
);
553 fpostinv
= new ExpStatement(Loc
.initial
, e
);
556 // Pre/Postcondition contract
558 funcdecl
.buildEnsureRequire();
561 if (needEnsure || funcdecl
.addPostInvariant())
563 /* https://issues.dlang.org/show_bug.cgi?id=3657
564 * Set the correct end line number for fensure scope.
566 uint fensure_endlin
= funcdecl
.endloc
.linnum
;
567 if (funcdecl
.fensure
)
568 if (auto s
= funcdecl
.fensure
.isScopeStatement())
569 fensure_endlin
= s
.endloc
.linnum
;
571 if ((needEnsure
&& global
.params
.useOut
== CHECKENABLE
.on
) || fpostinv
)
573 funcdecl
.returnLabel
= funcdecl
.searchLabel(Id
.returnLabel
);
576 // scope of out contract (need for vresult.semantic)
577 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
578 sym
.parent
= sc2
.scopesym
;
579 sym
.endlinnum
= fensure_endlin
;
580 scout
= sc2
.push(sym
);
585 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
586 sym
.parent
= sc2
.scopesym
;
587 sym
.endlinnum
= funcdecl
.endloc
.linnum
;
590 auto ad2
= funcdecl
.isMemberLocal();
592 /* If this is a class constructor
594 if (ad2
&& funcdecl
.isCtorDeclaration())
596 sc2
.ctorflow
.allocFieldinit(ad2
.fields
.length
);
597 foreach (v
; ad2
.fields
)
603 bool inferRef
= (f
.isref
&& (funcdecl
.storage_class
& STC
.auto_
));
605 funcdecl
.fbody
= funcdecl
.fbody
.statementSemantic(sc2
);
607 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, new Statements());
609 if (funcdecl
.isNaked())
611 fpreinv
= null; // can't accommodate with no stack frame
615 assert(funcdecl
.type
== f ||
(funcdecl
.type
.ty
== Tfunction
&& f
.purity
== PURE
.impure
&& (cast(TypeFunction
)funcdecl
.type
).purity
>= PURE
.fwdref
));
616 f
= cast(TypeFunction
)funcdecl
.type
;
618 if (funcdecl
.inferRetType
)
620 // If no return type inferred yet, then infer a void
623 if (f
.checkRetType(funcdecl
.loc
))
624 funcdecl
.fbody
= new ErrorStatement();
626 funcdecl
.checkMain(); // Check main() parameters and return type
630 f
.next
.checkComplexTransition(funcdecl
.loc
, sc
);
632 if (funcdecl
.returns
&& !funcdecl
.fbody
.isErrorStatement())
634 for (size_t i
= 0; i
< funcdecl
.returns
.length
;)
636 Expression exp
= (*funcdecl
.returns
)[i
].exp
;
637 if (exp
.op
== EXP
.variable
&& (cast(VarExp
)exp
).var
== funcdecl
.vresult
)
640 exp
.type
= Type
.tint32
;
643 // Remove `return vresult;` from returns
644 funcdecl
.returns
.remove(i
);
647 if (inferRef
&& f
.isref
&& !exp
.type
.constConv(f
.next
)) // https://issues.dlang.org/show_bug.cgi?id=13336
652 if (f
.isref
) // Function returns a reference
654 if (funcdecl
.storage_class
& STC
.auto_
)
655 funcdecl
.storage_class
&= ~STC
.auto_
;
659 if (!target
.isReturnOnStack(f
, funcdecl
.needThis()) ||
!funcdecl
.checkNRVO())
660 funcdecl
.isNRVO
= false;
662 if (funcdecl
.fbody
.isErrorStatement())
665 else if (funcdecl
.isStaticCtorDeclaration())
667 /* It's a static constructor. Ensure that all
668 * ctor consts were initialized.
670 ScopeDsymbol pd
= funcdecl
.toParent().isScopeDsymbol();
671 for (size_t i
= 0; i
< pd
.members
.length
; i
++)
673 Dsymbol s
= (*pd
.members
)[i
];
674 s
.checkCtorConstInit();
677 else if (ad2
&& funcdecl
.isCtorDeclaration())
679 ClassDeclaration cd
= ad2
.isClassDeclaration();
681 // Verify that all the ctorinit fields got initialized
682 if (!(sc2
.ctorflow
.callSuper
& CSX
.this_ctor
))
684 foreach (i
, v
; ad2
.fields
)
686 if (v
.isThisDeclaration())
690 /* Current bugs in the flow analysis:
691 * 1. union members should not produce error messages even if
693 * 2. structs should recognize delegating opAssign calls as well
694 * as delegating calls to other constructors
696 if (v
.isCtorinit() && !v
.type
.isMutable() && cd
)
697 .error(funcdecl
.loc
, "%s `%s` missing initializer for %s field `%s`", funcdecl
.kind
, funcdecl
.toPrettyChars
, MODtoChars(v
.type
.mod
), v
.toChars());
698 else if (v
.storage_class
& STC
.nodefaultctor
)
699 error(funcdecl
.loc
, "field `%s` must be initialized in constructor", v
.toChars());
700 else if (v
.type
.needsNested())
701 error(funcdecl
.loc
, "field `%s` must be initialized in constructor, because it is nested struct", v
.toChars());
705 bool mustInit
= (v
.storage_class
& STC
.nodefaultctor || v
.type
.needsNested());
706 if (mustInit
&& !(sc2
.ctorflow
.fieldinit
[i
].csx
& CSX
.this_ctor
))
708 .error(funcdecl
.loc
, "%s `%s` field `%s` must be initialized but skipped", funcdecl
.kind
, funcdecl
.toPrettyChars
, v
.toChars());
713 sc2
.ctorflow
.freeFieldinit();
715 if (cd
&& !(sc2
.ctorflow
.callSuper
& (CSX
.any_ctor | CSX
.halt
)) && cd
.baseClass
&& cd
.baseClass
.ctor
)
717 sc2
.ctorflow
.callSuper
= CSX
.none
;
719 // Insert implicit super() at start of fbody
720 Type tthis
= ad2
.type
.addMod(funcdecl
.vthis
.type
.mod
);
721 FuncDeclaration fd
= resolveFuncCall(Loc
.initial
, sc2
, cd
.baseClass
.ctor
, null, tthis
, ArgumentList(), FuncResolveFlag
.quiet
);
724 .error(funcdecl
.loc
, "%s `%s` no match for implicit `super()` call in constructor", funcdecl
.kind
, funcdecl
.toPrettyChars
);
726 else if (fd
.storage_class
& STC
.disable
)
728 .error(funcdecl
.loc
, "%s `%s` cannot call `super()` implicitly because it is annotated with `@disable`", funcdecl
.kind
, funcdecl
.toPrettyChars
);
732 Expression e1
= new SuperExp(Loc
.initial
);
733 Expression e
= new CallExp(Loc
.initial
, e1
);
734 e
= e
.expressionSemantic(sc2
);
735 Statement s
= new ExpStatement(Loc
.initial
, e
);
736 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, s
, funcdecl
.fbody
);
739 //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper);
742 /* https://issues.dlang.org/show_bug.cgi?id=17502
743 * Wait until after the return type has been inferred before
744 * generating the contracts for this function, and merging contracts
747 * https://issues.dlang.org/show_bug.cgi?id=17893
748 * However should take care to generate this before inferered
749 * function attributes are applied, such as 'nothrow'.
751 * This was originally at the end of the first semantic pass, but
752 * required a fix-up to be done here for the '__result' variable
753 * type of __ensure() inside auto functions, but this didn't work
754 * if the out parameter was implicit.
756 funcdecl
.buildEnsureRequire();
758 // Check for errors related to 'nothrow'.
759 const blockexit
= funcdecl
.fbody
.blockExit(funcdecl
, f
.isnothrow ? global
.errorSink
: null);
760 if (f
.isnothrow
&& blockexit
& BE
.throw_
)
761 error(funcdecl
.loc
, "%s `%s` may throw but is marked as `nothrow`", funcdecl
.kind(), funcdecl
.toPrettyChars());
763 if (!(blockexit
& (BE
.throw_ | BE
.halt
) || funcdecl
.hasCatches
))
765 /* Don't generate unwind tables for this function
766 * https://issues.dlang.org/show_bug.cgi?id=17997
768 funcdecl
.hasNoEH
= true;
771 if (funcdecl
.nothrowInprocess
)
773 if (funcdecl
.type
== f
)
774 f
= cast(TypeFunction
)f
.copy();
775 f
.isnothrow
= !(blockexit
& BE
.throw_
);
778 if (funcdecl
.fbody
.isErrorStatement())
781 else if (ad2
&& funcdecl
.isCtorDeclaration())
787 if (blockexit
& BE
.fallthru
)
789 Statement s
= new ReturnStatement(funcdecl
.loc
, null);
790 s
= s
.statementSemantic(sc2
);
791 funcdecl
.fbody
= new CompoundStatement(funcdecl
.loc
, funcdecl
.fbody
, s
);
792 funcdecl
.hasReturnExp |
= (funcdecl
.hasReturnExp
& 1 ?
16 : 1);
795 else if (funcdecl
.fes
)
797 // For foreach(){} body, append a return 0;
798 if (blockexit
& BE
.fallthru
)
800 Expression e
= IntegerExp
.literal
!0;
801 Statement s
= new ReturnStatement(Loc
.initial
, e
);
802 funcdecl
.fbody
= new CompoundStatement(Loc
.initial
, funcdecl
.fbody
, s
);
803 funcdecl
.hasReturnExp |
= (funcdecl
.hasReturnExp
& 1 ?
16 : 1);
805 assert(!funcdecl
.returnLabel
);
807 else if (f
.next
.toBasetype().ty
== Tnoreturn
)
809 // Fallthrough despite being declared as noreturn? return is already rejected when evaluating the ReturnStatement
810 if (blockexit
& BE
.fallthru
)
812 .error(funcdecl
.loc
, "%s `%s` is typed as `%s` but does return", funcdecl
.kind
, funcdecl
.toPrettyChars
, f
.next
.toChars());
813 funcdecl
.loc
.errorSupplemental("`noreturn` functions must either throw, abort or loop indefinitely");
818 const(bool) inlineAsm
= (funcdecl
.hasReturnExp
& 8) != 0;
819 if ((blockexit
& BE
.fallthru
) && f
.next
.ty
!= Tvoid
&& !inlineAsm
&& !(sc
.flags
& SCOPE
.Cfile
))
821 if (!funcdecl
.hasReturnExp
)
822 .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());
824 .error(funcdecl
.loc
, "%s `%s` no `return exp;` or `assert(0);` at end of function", funcdecl
.kind
, funcdecl
.toPrettyChars
);
828 if (funcdecl
.returns
)
830 bool implicit0
= addReturn0();
831 Type tret
= implicit0 ? Type
.tint32
: f
.next
;
832 assert(tret
.ty
!= Tvoid
);
833 if (funcdecl
.vresult || funcdecl
.returnLabel
)
834 funcdecl
.buildResultVar(scout ? scout
: sc2
, tret
);
836 /* Cannot move this loop into NrvoWalker, because
837 * returns[i] may be in the nested delegate for foreach-body.
839 for (size_t i
= 0; i
< funcdecl
.returns
.length
; i
++)
841 ReturnStatement rs
= (*funcdecl
.returns
)[i
];
842 Expression exp
= rs
.exp
;
843 if (exp
.op
== EXP
.error
)
845 if (tret
.ty
== Terror
)
847 // https://issues.dlang.org/show_bug.cgi?id=13702
848 exp
= checkGC(sc2
, exp
);
852 /* If the expression in the return statement (exp) cannot be implicitly
853 * converted to the return type (tret) of the function and if the
854 * type of the expression is type isolated, then it may be possible
855 * that a promotion to `immutable` or `inout` (through a cast) will
856 * match the return type.
858 if (!exp
.implicitConvTo(tret
) && funcdecl
.isTypeIsolated(exp
.type
))
860 /* https://issues.dlang.org/show_bug.cgi?id=20073
862 * The problem is that if the type of the returned expression (exp.type)
863 * is an aggregated declaration with an alias this, the alias this may be
864 * used for the conversion testing without it being an isolated type.
866 * To make sure this does not happen, we can test here the implicit conversion
867 * only for the aggregated declaration type by using `implicitConvToWithoutAliasThis`.
868 * The implicit conversion with alias this is taken care of later.
870 AggregateDeclaration aggDecl
= isAggregate(exp
.type
);
874 if (aggDecl
&& aggDecl
.aliasthis
)
877 tclass
= exp
.type
.isTypeClass();
879 tstruct
= exp
.type
.isTypeStruct();
880 assert(tclass || tstruct
);
886 if ((cast(TypeClass
)(exp
.type
.immutableOf())).implicitConvToWithoutAliasThis(tret
))
887 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
888 else if ((cast(TypeClass
)(exp
.type
.wildOf())).implicitConvToWithoutAliasThis(tret
))
889 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
893 if ((cast(TypeStruct
)exp
.type
.immutableOf()).implicitConvToWithoutAliasThis(tret
))
894 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
895 else if ((cast(TypeStruct
)exp
.type
.immutableOf()).implicitConvToWithoutAliasThis(tret
))
896 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
901 if (exp
.type
.immutableOf().implicitConvTo(tret
))
902 exp
= exp
.castTo(sc2
, exp
.type
.immutableOf());
903 else if (exp
.type
.wildOf().implicitConvTo(tret
))
904 exp
= exp
.castTo(sc2
, exp
.type
.wildOf());
908 const hasCopyCtor
= exp
.type
.ty
== Tstruct
&& (cast(TypeStruct
)exp
.type
).sym
.hasCopyCtor
;
909 // if a copy constructor is present, the return type conversion will be handled by it
910 if (!(hasCopyCtor
&& exp
.isLvalue()))
912 if (f
.isref
&& !MODimplicitConv(exp
.type
.mod
, tret
.mod
) && !tret
.isTypeSArray())
913 error(exp
.loc
, "expression `%s` of type `%s` is not implicitly convertible to return type `ref %s`",
914 exp
.toChars(), exp
.type
.toChars(), tret
.toChars());
916 exp
= exp
.implicitCastTo(sc2
, tret
);
921 // Function returns a reference
922 exp
= exp
.toLvalue(sc2
, "`ref` return");
923 checkReturnEscapeRef(sc2
, exp
, false);
924 exp
= exp
.optimize(WANTvalue
, /*keepLvalue*/ true);
928 exp
= exp
.optimize(WANTvalue
);
930 /* https://issues.dlang.org/show_bug.cgi?id=10789
931 * If NRVO is not possible, all returned lvalues should call their postblits.
933 if (!funcdecl
.isNRVO())
934 exp
= doCopyOrMove(sc2
, exp
, f
.next
);
936 if (tret
.hasPointers())
937 checkReturnEscape(sc2
, exp
, false);
940 exp
= checkGC(sc2
, exp
);
942 if (funcdecl
.vresult
)
944 // Create: return vresult = exp;
945 exp
= new BlitExp(rs
.loc
, funcdecl
.vresult
, exp
);
946 exp
.type
= funcdecl
.vresult
.type
;
949 exp
= Expression
.combine(exp
, new IntegerExp(rs
.caseDim
));
951 else if (funcdecl
.tintro
&& !tret
.equals(funcdecl
.tintro
.nextOf()))
953 exp
= exp
.implicitCastTo(sc2
, funcdecl
.tintro
.nextOf());
958 if (funcdecl
.nrvo_var || funcdecl
.returnLabel
)
960 scope NrvoWalker nw
= new NrvoWalker();
963 nw
.visitStmt(funcdecl
.fbody
);
969 if (global
.params
.inclusiveInContracts
)
971 funcdecl
.frequire
= funcdecl
.mergeFrequireInclusivePreview(
972 funcdecl
.frequire
, funcdecl
.fdrequireParams
);
976 funcdecl
.frequire
= funcdecl
.mergeFrequire(funcdecl
.frequire
, funcdecl
.fdrequireParams
);
978 funcdecl
.fensure
= funcdecl
.mergeFensure(funcdecl
.fensure
, Id
.result
, funcdecl
.fdensureParams
);
980 Statement freq
= funcdecl
.frequire
;
981 Statement fens
= funcdecl
.fensure
;
983 /* Do the semantic analysis on the [in] preconditions and
984 * [out] postconditions.
986 immutable bool isnothrow
= f
.isnothrow
&& !funcdecl
.nothrowInprocess
;
989 /* frequire is composed of the [in] contracts
991 auto sym
= new ScopeDsymbol(funcdecl
.loc
, null);
992 sym
.parent
= sc2
.scopesym
;
993 sym
.endlinnum
= funcdecl
.endloc
.linnum
;
995 sc2
.flags
= (sc2
.flags
& ~SCOPE
.contract
) | SCOPE
.require
;
997 // BUG: need to error if accessing out parameters
998 // BUG: need to disallow returns
999 // BUG: verify that all in and ref parameters are read
1000 freq
= freq
.statementSemantic(sc2
);
1002 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1003 const blockExit
= freq
.blockExit(funcdecl
, null);
1004 if (blockExit
& BE
.throw_
)
1007 // @@@DEPRECATED_2.111@@@
1008 // Deprecated in 2.101, can be made an error in 2.111
1009 deprecation(funcdecl
.loc
, "`%s`: `in` contract may throw but function is marked as `nothrow`",
1010 funcdecl
.toPrettyChars());
1011 else if (funcdecl
.nothrowInprocess
)
1012 f
.isnothrow
= false;
1015 funcdecl
.hasNoEH
= false;
1019 if (global
.params
.useIn
== CHECKENABLE
.off
)
1025 /* fensure is composed of the [out] contracts
1027 if (f
.next
.ty
== Tvoid
&& funcdecl
.fensures
)
1029 foreach (e
; *funcdecl
.fensures
)
1033 .error(e
.ensure
.loc
, "%s `%s` `void` functions have no result", funcdecl
.kind
, funcdecl
.toPrettyChars
);
1040 sc2
.flags
= (sc2
.flags
& ~SCOPE
.contract
) | SCOPE
.ensure
;
1042 // BUG: need to disallow returns and throws
1044 if (funcdecl
.fensure
&& f
.next
.ty
!= Tvoid
)
1045 funcdecl
.buildResultVar(scout
, f
.next
);
1047 fens
= fens
.statementSemantic(sc2
);
1049 // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
1050 const blockExit
= fens
.blockExit(funcdecl
, null);
1051 if (blockExit
& BE
.throw_
)
1054 // @@@DEPRECATED_2.111@@@
1055 // Deprecated in 2.101, can be made an error in 2.111
1056 deprecation(funcdecl
.loc
, "`%s`: `out` contract may throw but function is marked as `nothrow`",
1057 funcdecl
.toPrettyChars());
1058 else if (funcdecl
.nothrowInprocess
)
1059 f
.isnothrow
= false;
1062 funcdecl
.hasNoEH
= false;
1066 if (global
.params
.useOut
== CHECKENABLE
.off
)
1069 if (funcdecl
.fbody
&& funcdecl
.fbody
.isErrorStatement())
1074 auto a
= new Statements();
1075 // Merge in initialization of 'out' parameters
1076 if (funcdecl
.parameters
)
1078 for (size_t i
= 0; i
< funcdecl
.parameters
.length
; i
++)
1080 VarDeclaration v
= (*funcdecl
.parameters
)[i
];
1081 if (v
.storage_class
& STC
.out_
)
1085 .error(v
.loc
, "%s `%s` zero-length `out` parameters are not allowed.", v
.kind
, v
.toPrettyChars
);
1088 ExpInitializer ie
= v
._init
.isExpInitializer();
1090 if (auto iec
= ie
.exp
.isConstructExp())
1092 // construction occurred in parameter processing
1093 auto ec
= new AssignExp(iec
.loc
, iec
.e1
, iec
.e2
);
1097 a
.push(new ExpStatement(Loc
.initial
, ie
.exp
));
1104 /* Advance to elements[] member of TypeInfo_Tuple with:
1105 * _arguments = v_arguments.elements;
1107 Expression e
= new VarExp(Loc
.initial
, funcdecl
.v_arguments
);
1108 e
= new DotIdExp(Loc
.initial
, e
, Id
.elements
);
1109 e
= new ConstructExp(Loc
.initial
, _arguments
, e
);
1110 e
= e
.expressionSemantic(sc2
);
1112 _arguments
._init
= new ExpInitializer(Loc
.initial
, e
);
1113 auto de = new DeclarationExp(Loc
.initial
, _arguments
);
1114 a
.push(new ExpStatement(Loc
.initial
, de));
1117 // Merge contracts together with body into one compound statement
1119 if (freq || fpreinv
)
1124 freq
= new CompoundStatement(Loc
.initial
, freq
, fpreinv
);
1130 a
.push(funcdecl
.fbody
);
1132 if (fens || fpostinv
)
1137 fens
= new CompoundStatement(Loc
.initial
, fpostinv
, fens
);
1139 auto ls
= new LabelStatement(Loc
.initial
, Id
.returnLabel
, fens
);
1140 funcdecl
.returnLabel
.statement
= ls
;
1141 a
.push(funcdecl
.returnLabel
.statement
);
1143 if (f
.next
.ty
!= Tvoid
&& funcdecl
.vresult
)
1145 // Create: return vresult;
1146 Expression e
= new VarExp(Loc
.initial
, funcdecl
.vresult
);
1147 if (funcdecl
.tintro
)
1149 e
= e
.implicitCastTo(sc
, funcdecl
.tintro
.nextOf());
1150 e
= e
.expressionSemantic(sc
);
1152 auto s
= new ReturnStatement(Loc
.initial
, e
);
1158 // Add a return 0; statement
1159 Statement s
= new ReturnStatement(Loc
.initial
, IntegerExp
.literal
!0);
1163 Statement sbody
= new CompoundStatement(Loc
.initial
, a
);
1165 /* Append destructor calls for parameters as finally blocks.
1167 if (funcdecl
.parameters
)
1169 // check if callee destroys arguments
1170 const bool paramsNeedDtor
= target
.isCalleeDestroyingArgs(f
);
1172 foreach (v
; *funcdecl
.parameters
)
1174 if (v
.isReference() ||
(v
.storage_class
& STC
.lazy_
))
1176 if (v
.needsScopeDtor())
1178 v
.storage_class |
= STC
.nodtor
;
1179 if (!paramsNeedDtor
)
1182 // same with ExpStatement.scopeCode()
1183 Statement s
= new DtorExpStatement(Loc
.initial
, v
.edtor
, v
);
1185 s
= s
.statementSemantic(sc2
);
1187 const blockexit
= s
.blockExit(funcdecl
, isnothrow ? global
.errorSink
: null);
1188 if (blockexit
& BE
.throw_
)
1190 funcdecl
.hasNoEH
= false;
1192 error(funcdecl
.loc
, "%s `%s` may throw but is marked as `nothrow`", funcdecl
.kind(), funcdecl
.toPrettyChars());
1193 else if (funcdecl
.nothrowInprocess
)
1194 f
.isnothrow
= false;
1197 if (sbody
.blockExit(funcdecl
, f
.isnothrow ? global
.errorSink
: null) == BE
.fallthru
)
1198 sbody
= new CompoundStatement(Loc
.initial
, sbody
, s
);
1200 sbody
= new TryFinallyStatement(Loc
.initial
, sbody
, s
);
1204 // from this point on all possible 'throwers' are checked
1205 funcdecl
.nothrowInprocess
= false;
1207 if (funcdecl
.isSynchronized())
1209 /* Wrap the entire function body in a synchronized statement
1211 ClassDeclaration cd
= funcdecl
.toParentDecl().isClassDeclaration();
1214 if (target
.libraryObjectMonitors(funcdecl
, sbody
))
1217 if (funcdecl
.isStatic())
1219 // The monitor is in the ClassInfo
1220 vsync
= new DotIdExp(funcdecl
.loc
, symbolToExp(cd
, funcdecl
.loc
, sc2
, false), Id
.classinfo
);
1224 // 'this' is the monitor
1225 vsync
= new VarExp(funcdecl
.loc
, funcdecl
.vthis
);
1226 if (funcdecl
.hasDualContext())
1228 vsync
= new PtrExp(funcdecl
.loc
, vsync
);
1229 vsync
= new IndexExp(funcdecl
.loc
, vsync
, IntegerExp
.literal
!0);
1232 sbody
= new PeelStatement(sbody
); // don't redo semantic()
1233 sbody
= new SynchronizedStatement(funcdecl
.loc
, vsync
, sbody
);
1234 sbody
= sbody
.statementSemantic(sc2
);
1239 .error(funcdecl
.loc
, "%s `%s` synchronized function `%s` must be a member of a class", funcdecl
.kind
, funcdecl
.toPrettyChars
, funcdecl
.toChars());
1243 // If declaration has no body, don't set sbody to prevent incorrect codegen.
1244 if (funcdecl
.fbody || funcdecl
.allowsContractWithoutBody())
1245 funcdecl
.fbody
= sbody
;
1248 // Check for undefined labels
1249 if (funcdecl
.labtab
)
1250 foreach (keyValue
; funcdecl
.labtab
.tab
.asRange
)
1252 //printf(" KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
1253 LabelDsymbol label
= cast(LabelDsymbol
)keyValue
.value
;
1254 if (!label
.statement
&& (!label
.deleted || label
.iasm
))
1256 .error(label
.loc
, "%s `%s` label `%s` is undefined", funcdecl
.kind
, funcdecl
.toPrettyChars
, label
.toChars());
1260 // Fix up forward-referenced gotos
1261 if (funcdecl
.gotos
&& !funcdecl
.isCsymbol())
1263 for (size_t i
= 0; i
< funcdecl
.gotos
.length
; ++i
)
1265 (*funcdecl
.gotos
)[i
].checkLabel();
1269 if (funcdecl
.isNaked() && (funcdecl
.fensures || funcdecl
.frequires
))
1270 .error(funcdecl
.loc
, "%s `%s` naked assembly functions with contracts are not supported", funcdecl
.kind
, funcdecl
.toPrettyChars
);
1272 sc2
.ctorflow
.callSuper
= CSX
.none
;
1276 if (funcdecl
.checkClosure())
1278 // We should be setting errors here instead of relying on the global error count.
1282 /* If function survived being marked as impure, then it is pure
1284 if (funcdecl
.purityInprocess
)
1286 funcdecl
.purityInprocess
= false;
1287 if (funcdecl
.type
== f
)
1288 f
= cast(TypeFunction
)f
.copy();
1289 f
.purity
= PURE
.fwdref
;
1292 if (funcdecl
.safetyInprocess
)
1294 funcdecl
.safetyInprocess
= false;
1295 if (funcdecl
.type
== f
)
1296 f
= cast(TypeFunction
)f
.copy();
1297 f
.trust
= TRUST
.safe
;
1300 if (funcdecl
.nogcInprocess
)
1302 funcdecl
.nogcInprocess
= false;
1303 if (funcdecl
.type
== f
)
1304 f
= cast(TypeFunction
)f
.copy();
1308 finishScopeParamInference(funcdecl
, f
);
1310 // reset deco to apply inference result to mangled name
1311 if (f
!= funcdecl
.type
)
1314 // Do semantic type AFTER pure/nothrow inference.
1315 if (!f
.deco
&& funcdecl
.ident
!= Id
.xopEquals
&& funcdecl
.ident
!= Id
.xopCmp
)
1318 if (funcdecl
.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
1321 sc
.linkage
= funcdecl
._linkage
; // https://issues.dlang.org/show_bug.cgi?id=8496
1322 funcdecl
.type
= f
.typeSemantic(funcdecl
.loc
, sc
);
1326 // Check `extern(C++)` functions for invalid the return/parameter types
1327 if (funcdecl
._linkage
== LINK
.cpp
)
1329 static bool isCppNonMappableType(Type type
, Parameter param
= null, Type origType
= null)
1331 // Don't allow D `immutable` and `shared` types to be interfaced with C++
1332 if (type
.isImmutable() || type
.isShared())
1334 else if (Type cpptype
= target
.cpp
.parameterType(type
))
1337 if (origType
is null)
1340 // Permit types that are handled by toCppMangle. This list should be kept in sync with
1341 // each visit method in dmd.cppmangle and dmd.cppmanglewin.
1358 if (!origType
.isTypePointer())
1363 if (!type
.isTypeBasic())
1368 // Descend to the enclosing type
1369 if (auto tnext
= type
.nextOf())
1370 return isCppNonMappableType(tnext
, param
, origType
);
1374 if (isCppNonMappableType(f
.next
.toBasetype()))
1376 .error(funcdecl
.loc
, "%s `%s` cannot return type `%s` because its linkage is `extern(C++)`", funcdecl
.kind
, funcdecl
.toPrettyChars
, f
.next
.toChars());
1377 if (f
.next
.isTypeDArray())
1378 errorSupplemental(funcdecl
.loc
, "slices are specific to D and do not have a counterpart representation in C++", f
.next
.toChars());
1379 funcdecl
.errors
= true;
1381 foreach (i
, param
; f
.parameterList
)
1383 if (isCppNonMappableType(param
.type
.toBasetype(), param
))
1385 .error(funcdecl
.loc
, "%s `%s` cannot have parameter of type `%s` because its linkage is `extern(C++)`", funcdecl
.kind
, funcdecl
.toPrettyChars
, param
.type
.toChars());
1386 if (param
.type
.toBasetype().isTypeSArray())
1387 errorSupplemental(funcdecl
.loc
, "perhaps use a `%s*` type instead",
1388 param
.type
.nextOf().mutableOf().unSharedOf().toChars());
1389 funcdecl
.errors
= true;
1395 if (global
.params
.useDIP1021
&& funcdecl
.fbody
&& funcdecl
.type
.ty
!= Terror
&&
1396 funcdecl
.type
.isTypeFunction().islive
)
1401 /* If this function had instantiated with gagging, error reproduction will be
1402 * done by TemplateInstance::semantic.
1403 * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
1405 funcdecl
.semanticRun
= PASS
.semantic3done
;
1406 if ((global
.errors
!= oldErrors
) ||
(funcdecl
.fbody
&& funcdecl
.fbody
.isErrorStatement()))
1407 funcdecl
.hasSemantic3Errors
= true;
1409 funcdecl
.hasSemantic3Errors
= false;
1410 if (funcdecl
.type
.ty
== Terror
)
1411 funcdecl
.errors
= true;
1412 //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars());
1416 override void visit(CtorDeclaration ctor
)
1418 //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars());
1419 if (ctor
.semanticRun
>= PASS
.semantic3
)
1422 /* If any of the fields of the aggregate have a destructor, add
1423 * scope (failure) { this.fieldDtor(); }
1424 * as the first statement of the constructor (unless the constructor
1425 * doesn't define a body - @disable, extern)
1426 *.It is not necessary to add it after
1427 * each initialization of a field, because destruction of .init constructed
1428 * structs should be benign.
1429 * https://issues.dlang.org/show_bug.cgi?id=14246
1431 AggregateDeclaration ad
= ctor
.isMemberDecl();
1432 if (!ctor
.fbody ||
!ad ||
!ad
.fieldDtor ||
1433 global
.params
.dtorFields
== FeatureState
.disabled ||
!global
.params
.useExceptions || ctor
.type
.toTypeFunction
.isnothrow
)
1434 return visit(cast(FuncDeclaration
)ctor
);
1439 Expression e
= new ThisExp(ctor
.loc
);
1440 e
.type
= ad
.type
.mutableOf();
1441 e
= new DotVarExp(ctor
.loc
, e
, ad
.fieldDtor
, false);
1442 auto ce
= new CallExp(ctor
.loc
, e
);
1443 auto sexp
= new ExpStatement(ctor
.loc
, ce
);
1444 auto ss
= new ScopeStatement(ctor
.loc
, sexp
, ctor
.loc
);
1446 // @@@DEPRECATED_2.106@@@
1447 // Allow negligible attribute violations to allow for a smooth
1448 // transition. Remove this after the usual deprecation period
1450 if (global
.params
.dtorFields
== FeatureState
.default_
)
1452 auto ctf
= cast(TypeFunction
) ctor
.type
;
1453 auto dtf
= cast(TypeFunction
) ad
.fieldDtor
.type
;
1455 const ngErr
= ctf
.isnogc
&& !dtf
.isnogc
;
1456 const puErr
= ctf
.purity
&& !dtf
.purity
;
1457 const saErr
= ctf
.trust
== TRUST
.safe
&& dtf
.trust
<= TRUST
.system
;
1459 if (ngErr || puErr || saErr
)
1461 // storage_class is apparently not set for dtor & ctor
1464 (ngErr ? STC
.nogc
: 0) |
1465 (puErr ? STC
.pure_
: 0) |
1466 (saErr ? STC
.system
: 0)
1468 ctor
.loc
.deprecation("`%s` has stricter attributes than its destructor (`%s`)", ctor
.toPrettyChars(), ob
.peekChars());
1469 ctor
.loc
.deprecationSupplemental("The destructor will be called if an exception is thrown");
1470 ctor
.loc
.deprecationSupplemental("Either make the constructor `nothrow` or adjust the field destructors");
1472 ce
.ignoreAttributes
= true;
1479 * try { ctor.fbody; }
1480 * catch (Exception __o)
1481 * { this.fieldDtor(); throw __o; }
1482 * This differs from the alternate scope(failure) version in that an Exception
1483 * is caught rather than a Throwable. This enables the optimization whereby
1484 * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only
1485 * applies to Exception.)
1487 Identifier id
= Identifier
.generateId("__o");
1488 auto ts
= new ThrowStatement(ctor
.loc
, new IdentifierExp(ctor
.loc
, id
));
1489 auto handler
= new CompoundStatement(ctor
.loc
, ss
, ts
);
1491 auto catches
= new Catches();
1492 auto ctch
= new Catch(ctor
.loc
, getException(), id
, handler
);
1495 ctor
.fbody
= new TryCatchStatement(ctor
.loc
, ctor
.fbody
, catches
);
1500 * scope (failure) { this.fieldDtor(); }
1501 * Hopefully we can use this version someday when scope(failure) catches
1502 * Exception instead of Throwable.
1504 auto s
= new ScopeGuardStatement(ctor
.loc
, TOK
.onScopeFailure
, ss
);
1505 ctor
.fbody
= new CompoundStatement(ctor
.loc
, s
, ctor
.fbody
);
1507 visit(cast(FuncDeclaration
)ctor
);
1511 override void visit(Nspace ns
)
1513 if (ns
.semanticRun
>= PASS
.semantic3
)
1515 ns
.semanticRun
= PASS
.semantic3
;
1518 printf("Nspace::semantic3('%s')\n", ns
.toChars());
1524 sc
.linkage
= LINK
.cpp
;
1525 foreach (s
; *ns
.members
)
1532 override void visit(AttribDeclaration ad
)
1534 Dsymbols
* d
= ad
.include(sc
);
1538 Scope
* sc2
= ad
.newScope(sc
);
1539 for (size_t i
= 0; i
< d
.length
; i
++)
1541 Dsymbol s
= (*d
)[i
];
1548 override void visit(AggregateDeclaration ad
)
1550 //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors);
1554 StructDeclaration sd
= ad
.isStructDeclaration();
1555 if (!sc
) // from runDeferredSemantic3 for TypeInfo generation
1558 sd
.semanticTypeInfoMembers();
1562 auto sc2
= ad
.newScope(sc
);
1564 for (size_t i
= 0; i
< ad
.members
.length
; i
++)
1566 Dsymbol s
= (*ad
.members
)[i
];
1572 // Instantiate RTInfo!S to provide a pointer bitmap for the GC
1573 // Don't do it in -betterC or on unused deprecated / error types
1574 if (!ad
.getRTInfo
&& global
.params
.useTypeInfo
&& Type
.rtinfo
&&
1575 (!ad
.isDeprecated() || global
.params
.useDeprecated
!= DiagnosticReporting
.error
) &&
1576 (ad
.type
&& ad
.type
.ty
!= Terror
))
1578 // Evaluate: RTinfo!type
1579 auto tiargs
= new Objects();
1580 tiargs
.push(ad
.type
);
1581 auto ti
= new TemplateInstance(ad
.loc
, Type
.rtinfo
, tiargs
);
1583 Scope
* sc3
= ti
.tempdecl
._scope
.startCTFE();
1584 sc3
.tinst
= sc
.tinst
;
1585 sc3
.minst
= sc
.minst
;
1586 if (ad
.isDeprecated())
1587 sc3
.stc |
= STC
.deprecated_
;
1589 ti
.dsymbolSemantic(sc3
);
1592 auto e
= symbolToExp(ti
.toAlias(), Loc
.initial
, sc3
, false);
1596 e
= e
.ctfeInterpret();
1600 sd
.semanticTypeInfoMembers();
1601 ad
.semanticRun
= PASS
.semantic3done
;
1605 private struct FuncDeclSem3
1607 // The FuncDeclaration subject to Semantic analysis
1608 FuncDeclaration funcdecl
;
1610 // Scope of analysis
1612 this(FuncDeclaration fd
,Scope
* s
) scope @safe
1618 /* Checks that the overridden functions (if any) have in contracts if
1619 * funcdecl has an in contract.
1621 void checkInContractOverrides()
1623 if (funcdecl
.frequires
)
1625 for (size_t i
= 0; i
< funcdecl
.foverrides
.length
; i
++)
1627 FuncDeclaration fdv
= funcdecl
.foverrides
[i
];
1628 if (fdv
.fbody
&& !fdv
.frequires
)
1630 .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());
1638 extern (C
++) void semanticTypeInfoMembers(StructDeclaration sd
)
1642 sd
.xeq
.semanticRun
< PASS
.semantic3done
)
1644 uint errors
= global
.startGagging();
1645 sd
.xeq
.semantic3(sd
.xeq
._scope
);
1646 if (global
.endGagging(errors
))
1652 sd
.xcmp
.semanticRun
< PASS
.semantic3done
)
1654 uint errors
= global
.startGagging();
1655 sd
.xcmp
.semantic3(sd
.xcmp
._scope
);
1656 if (global
.endGagging(errors
))
1657 sd
.xcmp
= sd
.xerrcmp
;
1660 FuncDeclaration ftostr
= search_toString(sd
);
1663 ftostr
.semanticRun
< PASS
.semantic3done
)
1665 ftostr
.semantic3(ftostr
._scope
);
1670 sd
.xhash
.semanticRun
< PASS
.semantic3done
)
1672 sd
.xhash
.semantic3(sd
.xhash
._scope
);
1676 sd
.postblit
._scope
&&
1677 sd
.postblit
.semanticRun
< PASS
.semantic3done
)
1679 sd
.postblit
.semantic3(sd
.postblit
._scope
);
1684 sd
.dtor
.semanticRun
< PASS
.semantic3done
)
1686 sd
.dtor
.semantic3(sd
.dtor
._scope
);