2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
10 #include "root/dsystem.h"
11 #include "root/rmem.h"
12 #include "root/checkedint.h"
15 #include "statement.h"
17 #include "expression.h"
20 #include "staticassert.h"
23 #include "declaration.h"
24 #include "aggregate.h"
32 StorageClass
mergeFuncAttrs(StorageClass s1
, FuncDeclaration
*f
);
33 bool checkReturnEscapeRef(Scope
*sc
, Expression
*e
, bool gag
);
34 bool checkThrowEscape(Scope
*sc
, Expression
*e
, bool gag
);
35 LabelStatement
*checkLabeledLoop(Scope
*sc
, Statement
*statement
);
36 Identifier
*fixupLabelName(Scope
*sc
, Identifier
*ident
);
37 FuncDeclaration
*isFuncAddress(Expression
*e
, bool *hasOverloads
= NULL
);
38 VarDeclaration
*copyToTemp(StorageClass stc
, const char *name
, Expression
*e
);
39 Expression
*checkAssignmentAsCondition(Expression
*e
);
40 TypeIdentifier
*getThrowable();
42 int blockExit(Statement
*s
, FuncDeclaration
*func
, bool mustNotThrow
);
44 class StatementSemanticVisitor
: public Visitor
50 StatementSemanticVisitor(Scope
*sc
)
59 result
= new ErrorStatement();
63 void visit(Statement
*s
)
68 void visit(ErrorStatement
*s
)
73 void visit(PeelStatement
*s
)
75 /* "peel" off this wrapper, and don't run semantic()
81 void visit(ExpStatement
*s
)
85 //printf("ExpStatement::semantic() %s\n", s->exp->toChars());
87 // Allow CommaExp in ExpStatement because return isn't used
88 if (s
->exp
->op
== TOKcomma
)
89 ((CommaExp
*)s
->exp
)->allowCommaExp
= true;
91 s
->exp
= expressionSemantic(s
->exp
, sc
);
92 s
->exp
= resolveProperties(sc
, s
->exp
);
93 s
->exp
= s
->exp
->addDtorHook(sc
);
94 if (checkNonAssignmentArrayOp(s
->exp
))
95 s
->exp
= new ErrorExp();
96 if (FuncDeclaration
*f
= isFuncAddress(s
->exp
))
98 if (f
->checkForwardRef(s
->exp
->loc
))
99 s
->exp
= new ErrorExp();
101 if (discardValue(s
->exp
))
102 s
->exp
= new ErrorExp();
104 s
->exp
= s
->exp
->optimize(WANTvalue
);
105 s
->exp
= checkGC(sc
, s
->exp
);
106 if (s
->exp
->op
== TOKerror
)
112 void visit(CompileStatement
*cs
)
114 //printf("CompileStatement::semantic() %s\n", cs->exp->toChars());
115 Statements
*a
= cs
->flatten(sc
);
118 Statement
*s
= new CompoundStatement(cs
->loc
, a
);
119 result
= statementSemantic(s
, sc
);
122 void visit(CompoundStatement
*cs
)
124 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc);
125 for (size_t i
= 0; i
< cs
->statements
->length
; )
127 Statement
*s
= (*cs
->statements
)[i
];
130 Statements
*flt
= s
->flatten(sc
);
133 cs
->statements
->remove(i
);
134 cs
->statements
->insert(i
, flt
);
137 s
= statementSemantic(s
, sc
);
138 (*cs
->statements
)[i
] = s
;
142 Statement
*sexception
;
145 (*cs
->statements
)[i
] = s
->scopeCode(sc
, &sentry
, &sexception
, &sfinally
);
148 sentry
= statementSemantic(sentry
, sc
);
149 cs
->statements
->insert(i
, sentry
);
153 sexception
= statementSemantic(sexception
, sc
);
156 if (i
+ 1 == cs
->statements
->length
&& !sfinally
)
166 * catch (Throwable __o)
167 * { sexception; throw __o; }
169 Statements
*a
= new Statements();
170 for (size_t j
= i
+ 1; j
< cs
->statements
->length
; j
++)
172 a
->push((*cs
->statements
)[j
]);
174 Statement
*body
= new CompoundStatement(Loc(), a
);
175 body
= new ScopeStatement(Loc(), body
, Loc());
177 Identifier
*id
= Identifier::generateId("__o");
179 Statement
*handler
= new PeelStatement(sexception
);
180 if (blockExit(sexception
, sc
->func
, false) & BEfallthru
)
182 ThrowStatement
*ts
= new ThrowStatement(Loc(), new IdentifierExp(Loc(), id
));
183 ts
->internalThrow
= true;
184 handler
= new CompoundStatement(Loc(), handler
, ts
);
187 Catches
*catches
= new Catches();
188 Catch
*ctch
= new Catch(Loc(), getThrowable(), id
, handler
);
189 ctch
->internalCatch
= true;
192 s
= new TryCatchStatement(Loc(), body
, catches
);
194 s
= new TryFinallyStatement(Loc(), s
, sfinally
);
195 s
= statementSemantic(s
, sc
);
197 cs
->statements
->setDim(i
+ 1);
198 cs
->statements
->push(s
);
204 if (0 && i
+ 1 == cs
->statements
->length
)
206 cs
->statements
->push(sfinally
);
213 * s; try { s1; s2; } finally { sfinally; }
215 Statements
*a
= new Statements();
216 for (size_t j
= i
+ 1; j
< cs
->statements
->length
; j
++)
218 a
->push((*cs
->statements
)[j
]);
220 Statement
*body
= new CompoundStatement(Loc(), a
);
221 s
= new TryFinallyStatement(Loc(), body
, sfinally
);
222 s
= statementSemantic(s
, sc
);
223 cs
->statements
->setDim(i
+ 1);
224 cs
->statements
->push(s
);
231 /* Remove NULL statements from the list.
233 cs
->statements
->remove(i
);
239 for (size_t i
= 0; i
< cs
->statements
->length
; ++i
)
242 Statement
*s
= (*cs
->statements
)[i
];
246 Statement
*se
= s
->isErrorStatement();
253 /* Bugzilla 11653: 'semantic' may return another CompoundStatement
254 * (eg. CaseRangeStatement), so flatten it here.
256 Statements
*flt
= s
->flatten(sc
);
259 cs
->statements
->remove(i
);
260 cs
->statements
->insert(i
, flt
);
261 if (cs
->statements
->length
<= i
)
266 if (cs
->statements
->length
== 1)
268 result
= (*cs
->statements
)[0];
274 void visit(UnrolledLoopStatement
*uls
)
276 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc);
277 Scope
*scd
= sc
->push();
279 scd
->scontinue
= uls
;
281 Statement
*serror
= NULL
;
282 for (size_t i
= 0; i
< uls
->statements
->length
; i
++)
284 Statement
*s
= (*uls
->statements
)[i
];
287 //printf("[%d]: %s\n", i, s->toChars());
288 s
= statementSemantic(s
, scd
);
289 (*uls
->statements
)[i
] = s
;
292 serror
= s
->isErrorStatement();
297 result
= serror
? serror
: uls
;
300 void visit(ScopeStatement
*ss
)
302 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
305 ScopeDsymbol
*sym
= new ScopeDsymbol();
306 sym
->parent
= sc
->scopesym
;
307 sym
->endlinnum
= ss
->endloc
.linnum
;
310 Statements
*a
= ss
->statement
->flatten(sc
);
313 ss
->statement
= new CompoundStatement(ss
->loc
, a
);
316 ss
->statement
= statementSemantic(ss
->statement
, sc
);
319 if (ss
->statement
->isErrorStatement())
322 result
= ss
->statement
;
327 Statement
*sexception
;
330 ss
->statement
= ss
->statement
->scopeCode(sc
, &sentry
, &sexception
, &sfinally
);
335 //printf("adding sfinally\n");
336 sfinally
= statementSemantic(sfinally
, sc
);
337 ss
->statement
= new CompoundStatement(ss
->loc
, ss
->statement
, sfinally
);
346 void visit(ForwardingStatement
*ss
)
349 for (Scope
*csc
= sc
; !ss
->sym
->forward
; csc
= csc
->enclosing
)
352 ss
->sym
->forward
= csc
->scopesym
;
354 sc
= sc
->push(ss
->sym
);
357 ss
->statement
= statementSemantic(ss
->statement
, sc
);
359 result
= ss
->statement
;
362 void visit(WhileStatement
*ws
)
364 /* Rewrite as a for(;condition;) loop
366 Statement
*s
= new ForStatement(ws
->loc
, NULL
, ws
->condition
, NULL
, ws
->_body
, ws
->endloc
);
367 s
= statementSemantic(s
, sc
);
371 void visit(DoStatement
*ds
)
375 ds
->_body
= semanticScope(ds
->_body
, sc
, ds
, ds
);
378 if (ds
->condition
->op
== TOKdotid
)
379 ((DotIdExp
*)ds
->condition
)->noderef
= true;
381 // check in syntax level
382 ds
->condition
= checkAssignmentAsCondition(ds
->condition
);
384 ds
->condition
= expressionSemantic(ds
->condition
, sc
);
385 ds
->condition
= resolveProperties(sc
, ds
->condition
);
386 if (checkNonAssignmentArrayOp(ds
->condition
))
387 ds
->condition
= new ErrorExp();
388 ds
->condition
= ds
->condition
->optimize(WANTvalue
);
389 ds
->condition
= checkGC(sc
, ds
->condition
);
391 ds
->condition
= ds
->condition
->toBoolean(sc
);
393 if (ds
->condition
->op
== TOKerror
)
396 if (ds
->_body
&& ds
->_body
->isErrorStatement())
405 void visit(ForStatement
*fs
)
407 //printf("ForStatement::semantic %s\n", toChars());
412 * for (auto v1 = i1, v2 = i2; condition; increment) { ... }
414 * { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } }
420 * for (; condition; increment) { ... }
421 * } finally { v2.~this(); }
422 * } finally { v1.~this(); }
424 Statements
*ainit
= new Statements();
425 ainit
->push(fs
->_init
);
428 Statement
*s
= new CompoundStatement(fs
->loc
, ainit
);
429 s
= new ScopeStatement(fs
->loc
, s
, fs
->endloc
);
430 s
= statementSemantic(s
, sc
);
431 if (!s
->isErrorStatement())
433 if (LabelStatement
*ls
= checkLabeledLoop(sc
, fs
))
435 fs
->relatedLabeled
= s
;
440 assert(fs
->_init
== NULL
);
442 ScopeDsymbol
*sym
= new ScopeDsymbol();
443 sym
->parent
= sc
->scopesym
;
444 sym
->endlinnum
= fs
->endloc
.linnum
;
450 if (fs
->condition
->op
== TOKdotid
)
451 ((DotIdExp
*)fs
->condition
)->noderef
= true;
453 // check in syntax level
454 fs
->condition
= checkAssignmentAsCondition(fs
->condition
);
456 fs
->condition
= expressionSemantic(fs
->condition
, sc
);
457 fs
->condition
= resolveProperties(sc
, fs
->condition
);
458 if (checkNonAssignmentArrayOp(fs
->condition
))
459 fs
->condition
= new ErrorExp();
460 fs
->condition
= fs
->condition
->optimize(WANTvalue
);
461 fs
->condition
= checkGC(sc
, fs
->condition
);
462 fs
->condition
= fs
->condition
->toBoolean(sc
);
466 if (fs
->increment
->op
== TOKcomma
)
467 ((CommaExp
*)fs
->increment
)->allowCommaExp
= true;
468 fs
->increment
= expressionSemantic(fs
->increment
, sc
);
469 fs
->increment
= resolveProperties(sc
, fs
->increment
);
470 if (checkNonAssignmentArrayOp(fs
->increment
))
471 fs
->increment
= new ErrorExp();
472 fs
->increment
= fs
->increment
->optimize(WANTvalue
);
473 fs
->increment
= checkGC(sc
, fs
->increment
);
479 fs
->_body
= semanticNoScope(fs
->_body
, sc
);
484 if ((fs
->condition
&& fs
->condition
->op
== TOKerror
) ||
485 (fs
->increment
&& fs
->increment
->op
== TOKerror
) ||
486 (fs
->_body
&& fs
->_body
->isErrorStatement()))
492 /***********************
493 * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
496 * storageClass = The storage class of the variable.
497 * type = The declared type of the variable.
498 * ident = The name of the variable.
499 * e = The initializer of the variable (i.e. the current element of the looped over aggregate).
500 * t = The type of the initializer.
502 * `true` iff the declaration was successful.
504 bool declareVariable(ForeachStatement
*fs
, Type
*paramtype
, TupleExp
*te
,
505 bool needExpansion
, bool isStatic
, Statements
*statements
, Dsymbols
*declarations
,
506 StorageClass storageClass
, Type
*type
, Identifier
*ident
, Expression
*e
, Type
*t
)
509 if (storageClass
& (STCout
| STClazy
) ||
510 (storageClass
& STCref
&& !te
))
512 fs
->error("no storage class for value %s", ident
->toChars());
518 Type
*tb
= e
->type
->toBasetype();
520 if (!(storageClass
& STCmanifest
))
522 if ((isStatic
|| tb
->ty
== Tfunction
|| tb
->ty
== Tsarray
|| storageClass
& STCalias
) && e
->op
== TOKvar
)
523 ds
= ((VarExp
*)e
)->var
;
524 else if (e
->op
== TOKtemplate
)
525 ds
= ((TemplateExp
*)e
)->td
;
526 else if (e
->op
== TOKscope
)
527 ds
= ((ScopeExp
*)e
)->sds
;
528 else if (e
->op
== TOKfunction
)
530 FuncExp
*fe
= (FuncExp
*)e
;
531 ds
= fe
->td
? (Dsymbol
*)fe
->td
: fe
->fd
;
534 else if (storageClass
& STCalias
)
536 fs
->error("foreach loop variable cannot be both enum and alias");
542 var
= new AliasDeclaration(loc
, ident
, ds
);
543 if (storageClass
& STCref
)
545 fs
->error("symbol %s cannot be ref", ds
->toChars());
550 fs
->error("cannot specify element type for symbol %s", ds
->toChars());
554 else if (e
->op
== TOKtype
)
556 var
= new AliasDeclaration(loc
, ident
, e
->type
);
559 fs
->error("cannot specify element type for type %s", e
->type
->toChars());
565 e
= resolveProperties(sc
, e
);
569 Initializer
*ie
= new ExpInitializer(Loc(), e
);
570 VarDeclaration
*v
= new VarDeclaration(loc
, type
, ident
, ie
);
571 if (storageClass
& STCref
)
572 v
->storage_class
|= STCref
| STCforeach
;
573 if (isStatic
|| storageClass
& STCmanifest
|| e
->isConst() ||
574 e
->op
== TOKstring
||
575 e
->op
== TOKstructliteral
||
576 e
->op
== TOKarrayliteral
)
578 if (v
->storage_class
& STCref
)
580 if (!isStatic
|| !needExpansion
)
582 fs
->error("constant value %s cannot be ref", ie
->toChars());
586 fs
->error("constant value %s cannot be ref", ident
->toChars());
591 v
->storage_class
|= STCmanifest
;
598 var
= new AliasDeclaration(loc
, ident
, t
);
601 fs
->error("cannot specify element type for symbol %s", fs
->toChars());
606 var
->storage_class
|= STClocal
;
608 statements
->push(new ExpStatement(loc
, var
));
609 else if (declarations
)
610 declarations
->push(var
);
616 bool makeTupleForeachBody(ForeachStatement
*fs
, size_t k
,
617 Type
*paramtype
, TupleExp
*te
, TypeTuple
*tuple
,
618 bool needExpansion
, bool isStatic
, bool isDecl
,
619 Statements
*statements
, Dsymbols
*declarations
, Dsymbols
*dbody
)
622 Expression
*e
= NULL
;
627 t
= Parameter::getNth(tuple
->arguments
, k
)->type
;
628 Parameter
*p
= (*fs
->parameters
)[0];
629 Statements
*stmts
= (isDecl
) ? NULL
: new Statements();
630 Dsymbols
*decls
= (isDecl
) ? new Dsymbols() : NULL
;
632 size_t dim
= fs
->parameters
->length
;
633 if (!needExpansion
&& dim
== 2)
636 if (p
->storageClass
& (STCout
| STCref
| STClazy
))
638 fs
->error("no storage class for key %s", p
->ident
->toChars());
645 p
->type
= Type::tsize_t
;
648 p
->type
= typeSemantic(p
->type
, loc
, sc
);
649 TY keyty
= p
->type
->ty
;
650 if (keyty
!= Tint32
&& keyty
!= Tuns32
)
652 if (global
.params
.isLP64
)
654 if (keyty
!= Tint64
&& keyty
!= Tuns64
)
656 fs
->error("foreach: key type must be int or uint, long or ulong, not %s", p
->type
->toChars());
662 fs
->error("foreach: key type must be int or uint, not %s", p
->type
->toChars());
666 Initializer
*ie
= new ExpInitializer(Loc(), new IntegerExp(k
));
667 VarDeclaration
*var
= new VarDeclaration(loc
, p
->type
, p
->ident
, ie
);
668 var
->storage_class
|= STCmanifest
;
670 var
->storage_class
|= STClocal
;
672 stmts
->push(new ExpStatement(loc
, var
));
675 p
= (*fs
->parameters
)[1]; // value
678 if (!isStatic
|| !needExpansion
)
681 if (!declareVariable(fs
, paramtype
, te
, needExpansion
, isStatic
, stmts
, decls
,
682 p
->storageClass
, p
->type
, p
->ident
, e
, t
))
689 // expand tuples into multiple `static foreach` variables.
691 Identifier
*ident
= Identifier::generateId("__value");
692 declareVariable(fs
, paramtype
, te
, needExpansion
, isStatic
, stmts
, decls
,
693 0, e
->type
, ident
, e
, NULL
);
694 Identifier
*field
= Identifier::idPool("tuple");
695 Expression
*access
= new DotIdExp(loc
, e
, field
);
696 access
= expressionSemantic(access
, sc
);
699 //printf("%s\n", tuple->toChars());
700 for (size_t l
= 0; l
< dim
; l
++)
702 Parameter
*cp
= (*fs
->parameters
)[l
];
703 Expression
*init_
= new IndexExp(loc
, access
, new IntegerExp(loc
, l
, Type::tsize_t
));
704 init_
= expressionSemantic(init_
, sc
);
706 declareVariable(fs
, paramtype
, te
, needExpansion
, isStatic
, stmts
, decls
,
707 p
->storageClass
, init_
->type
, cp
->ident
, init_
, NULL
);
710 Statement
*fwdstmt
= NULL
;
711 Dsymbol
*fwddecl
= NULL
;
715 stmts
->push(fs
->_body
->syntaxCopy());
716 fwdstmt
= new CompoundStatement(loc
, stmts
);
720 decls
->append(Dsymbol::arraySyntaxCopy(dbody
));
724 fwdstmt
= new ScopeStatement(loc
, fwdstmt
, fs
->endloc
);
728 fwdstmt
= new ForwardingStatement(loc
, fwdstmt
);
732 fwddecl
= new ForwardingAttribDeclaration(decls
);
736 statements
->push(fwdstmt
);
737 else if (declarations
)
738 declarations
->push(fwddecl
);
745 * Type check and unroll `foreach` over an expression tuple as well
746 * as `static foreach` statements and `static foreach`
747 * declarations. For `static foreach` statements and `static
748 * foreach` declarations, the visitor interface is used (and the
749 * result is written into the `result` field.) For `static
750 * foreach` declarations, the resulting Dsymbols* are returned
753 * The unrolled body is wrapped into a
754 * - UnrolledLoopStatement, for `foreach` over an expression tuple.
755 * - ForwardingStatement, for `static foreach` statements.
756 * - ForwardingAttribDeclaration, for `static foreach` declarations.
758 * `static foreach` variables are declared as `STClocal`, such
759 * that they are inserted into the local symbol tables of the
760 * forwarding constructs instead of forwarded. For `static
761 * foreach` with multiple foreach loop variables whose aggregate
762 * has been lowered into a sequence of tuples, this function
763 * expands the tuples into multiple `STClocal` `static foreach`
766 bool makeTupleForeach(ForeachStatement
*fs
, bool needExpansion
, bool isStatic
, bool isDecl
,
767 Statements
*statements
, Dsymbols
*declarations
, Dsymbols
*dbody
)
770 size_t dim
= fs
->parameters
->length
;
771 if (!needExpansion
&& (dim
< 1 || dim
> 2))
773 fs
->error("only one (value) or two (key,value) arguments for tuple foreach");
777 Type
*paramtype
= (*fs
->parameters
)[dim
-1]->type
;
780 paramtype
= typeSemantic(paramtype
, loc
, sc
);
781 if (paramtype
->ty
== Terror
)
785 Type
*tab
= fs
->aggr
->type
->toBasetype();
786 TypeTuple
*tuple
= (TypeTuple
*)tab
;
787 //printf("aggr: op = %d, %s\n", fs->aggr->op, fs->aggr->toChars());
790 if (fs
->aggr
->op
== TOKtuple
) // expression tuple
792 te
= (TupleExp
*)fs
->aggr
;
793 n
= te
->exps
->length
;
795 else if (fs
->aggr
->op
== TOKtype
) // type tuple
797 n
= Parameter::dim(tuple
->arguments
);
801 for (size_t j
= 0; j
< n
; j
++)
803 size_t k
= (fs
->op
== TOKforeach
) ? j
: n
- 1 - j
;
804 if (!makeTupleForeachBody(fs
, k
, paramtype
, te
, tuple
,
805 needExpansion
, isStatic
, isDecl
,
806 statements
, declarations
, dbody
))
812 Dsymbols
*makeTupleForeachStaticDecl(ForeachStatement
*fs
, Dsymbols
*dbody
, bool needExpansion
)
815 Dsymbols
*declarations
= new Dsymbols();
816 if (!makeTupleForeach(fs
, needExpansion
, true, true, NULL
, declarations
, dbody
))
822 void makeTupleForeachStatic(ForeachStatement
*fs
, bool needExpansion
)
826 Statements
*statements
= new Statements();
827 if (!makeTupleForeach(fs
, needExpansion
, true, false, statements
, NULL
, NULL
))
830 result
= new CompoundStatement(loc
, statements
);
833 void visit(ForeachStatement
*fs
)
835 //printf("ForeachStatement::semantic() %p\n", fs);
839 size_t dim
= fs
->parameters
->length
;
840 TypeAArray
*taa
= NULL
;
841 Dsymbol
*sapply
= NULL
;
848 fs
->func
= fs
->func
->fes
->func
;
850 VarDeclaration
*vinit
= NULL
;
851 fs
->aggr
= expressionSemantic(fs
->aggr
, sc
);
852 fs
->aggr
= resolveProperties(sc
, fs
->aggr
);
853 fs
->aggr
= fs
->aggr
->optimize(WANTvalue
);
854 if (fs
->aggr
->op
== TOKerror
)
857 Expression
*oaggr
= fs
->aggr
;
858 if (fs
->aggr
->type
&& fs
->aggr
->type
->toBasetype()->ty
== Tstruct
&&
859 ((TypeStruct
*)(fs
->aggr
->type
->toBasetype()))->sym
->dtor
&&
860 fs
->aggr
->op
!= TOKtype
&& !fs
->aggr
->isLvalue())
862 // Bugzilla 14653: Extend the life of rvalue aggregate till the end of foreach.
863 vinit
= copyToTemp(STCrvalue
, "__aggr", fs
->aggr
);
864 dsymbolSemantic(vinit
, sc
);
865 fs
->aggr
= new VarExp(fs
->aggr
->loc
, vinit
);
868 if (!inferAggregate(fs
, sc
, sapply
))
870 const char *msg
= "";
871 if (fs
->aggr
->type
&& isAggregate(fs
->aggr
->type
))
873 msg
= ", define opApply(), range primitives, or use .tupleof";
875 fs
->error("invalid foreach aggregate %s%s", oaggr
->toChars(), msg
);
879 Dsymbol
* sapplyOld
= sapply
; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
881 /* Check for inference errors
883 if (!inferApplyArgTypes(fs
, sc
, sapply
))
886 Try and extract the parameter count of the opApply callback function, e.g.:
887 int opApply(int delegate(int, float)) => 2 args
889 bool foundMismatch
= false;
890 size_t foreachParamCount
= 0;
893 if (FuncDeclaration
*fd
= sapplyOld
->isFuncDeclaration())
895 ParameterList fparameters
= fd
->getParameterList();
897 if (fparameters
.length() == 1)
899 // first param should be the callback function
900 Parameter
*fparam
= fparameters
[0];
901 if ((fparam
->type
->ty
== Tpointer
|| fparam
->type
->ty
== Tdelegate
) &&
902 fparam
->type
->nextOf()->ty
== Tfunction
)
904 TypeFunction
*tf
= (TypeFunction
*)fparam
->type
->nextOf();
905 foreachParamCount
= tf
->parameterList
.length();
906 foundMismatch
= true;
912 //printf("dim = %d, parameters->length = %d\n", dim, fs->parameters->length);
913 if (foundMismatch
&& dim
!= foreachParamCount
)
915 const char *plural
= foreachParamCount
> 1 ? "s" : "";
916 fs
->error("cannot infer argument types, expected %d argument%s, not %d",
917 foreachParamCount
, plural
, dim
);
920 fs
->error("cannot uniquely infer foreach argument types");
925 Type
*tab
= fs
->aggr
->type
->toBasetype();
927 if (tab
->ty
== Ttuple
) // don't generate new scope for tuple loops
929 Statements
*statements
= new Statements();
930 if (!makeTupleForeach(fs
, false, false, false, statements
, NULL
, NULL
))
933 result
= new UnrolledLoopStatement(loc
, statements
);
934 if (LabelStatement
*ls
= checkLabeledLoop(sc
, fs
))
935 ls
->gotoTarget
= result
;
936 if (fs
->aggr
->op
== TOKtuple
)
938 TupleExp
*te
= (TupleExp
*)fs
->aggr
;
940 result
= new CompoundStatement(loc
, new ExpStatement(te
->e0
->loc
, te
->e0
), result
);
943 result
= new CompoundStatement(loc
, new ExpStatement(loc
, vinit
), result
);
944 result
= statementSemantic(result
, sc
);
948 sym
= new ScopeDsymbol();
949 sym
->parent
= sc
->scopesym
;
950 sym
->endlinnum
= fs
->endloc
.linnum
;
951 Scope
*sc2
= sc
->push(sym
);
955 for (size_t i
= 0; i
< dim
; i
++)
957 Parameter
*p
= (*fs
->parameters
)[i
];
958 if (p
->storageClass
& STCmanifest
)
960 fs
->error("cannot declare enum loop variables for non-unrolled foreach");
962 if (p
->storageClass
& STCalias
)
964 fs
->error("cannot declare alias loop variables for non-unrolled foreach");
973 if (fs
->checkForArgTypes())
979 if (dim
< 1 || dim
> 2)
981 fs
->error("only one or two arguments for array foreach");
985 // Finish semantic on all foreach parameter types.
986 for (size_t i
= 0; i
< dim
; i
++)
988 Parameter
*p
= (*fs
->parameters
)[i
];
989 p
->type
= typeSemantic(p
->type
, loc
, sc2
);
990 p
->type
= p
->type
->addStorageClass(p
->storageClass
);
993 tn
= tab
->nextOf()->toBasetype();
997 Type
*tindex
= (*fs
->parameters
)[0]->type
;
998 if (!tindex
->isintegral())
1000 fs
->error("foreach: key cannot be of non-integral type `%s`",
1004 /* What cases to deprecate implicit conversions for:
1005 * 1. foreach aggregate is a dynamic array
1006 * 2. foreach body is lowered to _aApply (see special case below).
1008 Type
*tv
= (*fs
->parameters
)[1]->type
->toBasetype();
1009 if ((tab
->ty
== Tarray
||
1010 (tn
->ty
!= tv
->ty
&&
1011 (tn
->ty
== Tchar
|| tn
->ty
== Twchar
|| tn
->ty
== Tdchar
) &&
1012 (tv
->ty
== Tchar
|| tv
->ty
== Twchar
|| tv
->ty
== Tdchar
))) &&
1013 !Type::tsize_t
->implicitConvTo(tindex
))
1015 fs
->deprecation("foreach: loop index implicitly converted from `size_t` to `%s`",
1020 /* Look for special case of parsing char types out of char type
1023 if (tn
->ty
== Tchar
|| tn
->ty
== Twchar
|| tn
->ty
== Tdchar
)
1025 int i
= (dim
== 1) ? 0 : 1; // index of value
1026 Parameter
*p
= (*fs
->parameters
)[i
];
1027 tnv
= p
->type
->toBasetype();
1028 if (tnv
->ty
!= tn
->ty
&&
1029 (tnv
->ty
== Tchar
|| tnv
->ty
== Twchar
|| tnv
->ty
== Tdchar
))
1031 if (p
->storageClass
& STCref
)
1033 fs
->error("foreach: value of UTF conversion cannot be ref");
1038 p
= (*fs
->parameters
)[0];
1039 if (p
->storageClass
& STCref
)
1041 fs
->error("foreach: key cannot be ref");
1049 for (size_t i
= 0; i
< dim
; i
++)
1051 // Declare parameterss
1052 Parameter
*p
= (*fs
->parameters
)[i
];
1053 VarDeclaration
*var
;
1055 if (dim
== 2 && i
== 0)
1057 var
= new VarDeclaration(loc
, p
->type
->mutableOf(), Identifier::generateId("__key"), NULL
);
1058 var
->storage_class
|= STCtemp
| STCforeach
;
1059 if (var
->storage_class
& (STCref
| STCout
))
1060 var
->storage_class
|= STCnodtor
;
1063 if (p
->storageClass
& STCref
)
1065 if (var
->type
->constConv(p
->type
) <= MATCHnomatch
)
1067 fs
->error("key type mismatch, %s to ref %s",
1068 var
->type
->toChars(), p
->type
->toChars());
1072 if (tab
->ty
== Tsarray
)
1074 TypeSArray
*ta
= (TypeSArray
*)tab
;
1075 IntRange dimrange
= getIntRange(ta
->dim
);
1076 if (!IntRange::fromType(var
->type
).contains(dimrange
))
1078 fs
->error("index type `%s` cannot cover index range 0..%llu", p
->type
->toChars(), ta
->dim
->toInteger());
1081 fs
->key
->range
= new IntRange(SignExtendedNumber(0), dimrange
.imax
);
1086 var
= new VarDeclaration(loc
, p
->type
, p
->ident
, NULL
);
1087 var
->storage_class
|= STCforeach
;
1088 var
->storage_class
|= p
->storageClass
& (STCin
| STCout
| STCref
| STC_TYPECTOR
);
1089 if (var
->storage_class
& (STCref
| STCout
))
1090 var
->storage_class
|= STCnodtor
;
1093 if (var
->storage_class
& STCref
)
1095 if (fs
->aggr
->checkModifiable(sc2
, 1) == 2)
1096 var
->storage_class
|= STCctorinit
;
1098 Type
*t
= tab
->nextOf();
1099 if (t
->constConv(p
->type
) <= MATCHnomatch
)
1101 fs
->error("argument type mismatch, %s to ref %s",
1102 t
->toChars(), p
->type
->toChars());
1109 /* Convert to a ForStatement
1110 * foreach (key, value; a) body =>
1111 * for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
1112 * { T value = tmp[k]; body }
1114 * foreach_reverse (key, value; a) body =>
1115 * for (T[] tmp = a[], size_t key = tmp.length; key--; )
1116 * { T value = tmp[k]; body }
1118 Identifier
*id
= Identifier::generateId("__r");
1119 ExpInitializer
*ie
= new ExpInitializer(loc
, new SliceExp(loc
, fs
->aggr
, NULL
, NULL
));
1120 VarDeclaration
*tmp
;
1121 if (fs
->aggr
->op
== TOKarrayliteral
&&
1122 !((*fs
->parameters
)[dim
- 1]->storageClass
& STCref
))
1124 ArrayLiteralExp
*ale
= (ArrayLiteralExp
*)fs
->aggr
;
1125 size_t edim
= ale
->elements
? ale
->elements
->length
: 0;
1126 Type
*telem
= (*fs
->parameters
)[dim
- 1]->type
;
1128 // Bugzilla 12936: if telem has been specified explicitly,
1129 // converting array literal elements to telem might make it @nogc.
1130 fs
->aggr
= fs
->aggr
->implicitCastTo(sc
, telem
->sarrayOf(edim
));
1131 if (fs
->aggr
->op
== TOKerror
)
1134 // for (T[edim] tmp = a, ...)
1135 tmp
= new VarDeclaration(loc
, fs
->aggr
->type
, id
, ie
);
1138 tmp
= new VarDeclaration(loc
, tab
->nextOf()->arrayOf(), id
, ie
);
1139 tmp
->storage_class
|= STCtemp
;
1140 tmp
->endlinnum
= fs
->endloc
.linnum
;
1142 Expression
*tmp_length
= new DotIdExp(loc
, new VarExp(loc
, tmp
), Id::length
);
1146 Identifier
*idkey
= Identifier::generateId("__key");
1147 fs
->key
= new VarDeclaration(loc
, Type::tsize_t
, idkey
, NULL
);
1148 fs
->key
->storage_class
|= STCtemp
;
1150 else if (fs
->key
->type
->ty
!= Type::tsize_t
->ty
)
1152 tmp_length
= new CastExp(loc
, tmp_length
, fs
->key
->type
);
1154 if (fs
->op
== TOKforeach_reverse
)
1155 fs
->key
->_init
= new ExpInitializer(loc
, tmp_length
);
1157 fs
->key
->_init
= new ExpInitializer(loc
, new IntegerExp(loc
, 0, fs
->key
->type
));
1159 Statements
*cs
= new Statements();
1161 cs
->push(new ExpStatement(loc
, vinit
));
1162 cs
->push(new ExpStatement(loc
, tmp
));
1163 cs
->push(new ExpStatement(loc
, fs
->key
));
1164 Statement
*forinit
= new CompoundDeclarationStatement(loc
, cs
);
1167 if (fs
->op
== TOKforeach_reverse
)
1170 cond
= new PostExp(TOKminusminus
, loc
, new VarExp(loc
, fs
->key
));
1175 cond
= new CmpExp(TOKlt
, loc
, new VarExp(loc
, fs
->key
), tmp_length
);
1178 Expression
*increment
= NULL
;
1179 if (fs
->op
== TOKforeach
)
1182 increment
= new AddAssignExp(loc
, new VarExp(loc
, fs
->key
), new IntegerExp(loc
, 1, fs
->key
->type
));
1185 // T value = tmp[key];
1186 IndexExp
*indexExp
= new IndexExp(loc
, new VarExp(loc
, tmp
), new VarExp(loc
, fs
->key
));
1187 indexExp
->indexIsInBounds
= true; // disabling bounds checking in foreach statements.
1188 fs
->value
->_init
= new ExpInitializer(loc
, indexExp
);
1189 Statement
*ds
= new ExpStatement(loc
, fs
->value
);
1193 Parameter
*p
= (*fs
->parameters
)[0];
1194 if ((p
->storageClass
& STCref
) && p
->type
->equals(fs
->key
->type
))
1196 fs
->key
->range
= NULL
;
1197 AliasDeclaration
*v
= new AliasDeclaration(loc
, p
->ident
, fs
->key
);
1198 fs
->_body
= new CompoundStatement(loc
, new ExpStatement(loc
, v
), fs
->_body
);
1202 ExpInitializer
*ei
= new ExpInitializer(loc
, new IdentifierExp(loc
, fs
->key
->ident
));
1203 VarDeclaration
*v
= new VarDeclaration(loc
, p
->type
, p
->ident
, ei
);
1204 v
->storage_class
|= STCforeach
| (p
->storageClass
& STCref
);
1205 fs
->_body
= new CompoundStatement(loc
, new ExpStatement(loc
, v
), fs
->_body
);
1206 if (fs
->key
->range
&& !p
->type
->isMutable())
1208 /* Limit the range of the key to the specified range
1210 v
->range
= new IntRange(fs
->key
->range
->imin
, fs
->key
->range
->imax
- SignExtendedNumber(1));
1214 fs
->_body
= new CompoundStatement(loc
, ds
, fs
->_body
);
1216 s
= new ForStatement(loc
, forinit
, cond
, increment
, fs
->_body
, fs
->endloc
);
1217 if (LabelStatement
*ls
= checkLabeledLoop(sc
, fs
)) // Bugzilla 15450: don't use sc2
1219 s
= statementSemantic(s
, sc2
);
1224 if (fs
->op
== TOKforeach_reverse
)
1225 fs
->warning("cannot use foreach_reverse with an associative array");
1226 if (fs
->checkForArgTypes())
1232 taa
= (TypeAArray
*)tab
;
1233 if (dim
< 1 || dim
> 2)
1235 fs
->error("only one or two arguments for associative array foreach");
1242 /* Prefer using opApply, if it exists
1248 /* Look for range iteration, i.e. the properties
1249 * .empty, .popFront, .popBack, .front and .back
1250 * foreach (e; aggr) { ... }
1252 * for (auto __r = aggr[]; !__r.empty; __r.popFront()) {
1253 * auto e = __r.front;
1257 AggregateDeclaration
*ad
= (tab
->ty
== Tclass
)
1258 ? (AggregateDeclaration
*)((TypeClass
*)tab
)->sym
1259 : (AggregateDeclaration
*)((TypeStruct
*)tab
)->sym
;
1260 Identifier
*idfront
;
1261 Identifier
*idpopFront
;
1262 if (fs
->op
== TOKforeach
)
1264 idfront
= Id::Ffront
;
1265 idpopFront
= Id::FpopFront
;
1269 idfront
= Id::Fback
;
1270 idpopFront
= Id::FpopBack
;
1272 Dsymbol
*sfront
= ad
->search(Loc(), idfront
);
1276 /* Generate a temporary __r and initialize it with the aggregate.
1280 if (vinit
&& fs
->aggr
->op
== TOKvar
&& ((VarExp
*)fs
->aggr
)->var
== vinit
)
1283 init
= new ExpStatement(loc
, vinit
);
1287 r
= copyToTemp(0, "__r", fs
->aggr
);
1288 dsymbolSemantic(r
, sc
);
1289 init
= new ExpStatement(loc
, r
);
1291 init
= new CompoundStatement(loc
, new ExpStatement(loc
, vinit
), init
);
1295 Expression
*e
= new VarExp(loc
, r
);
1296 e
= new DotIdExp(loc
, e
, Id::Fempty
);
1297 Expression
*condition
= new NotExp(loc
, e
);
1300 e
= new VarExp(loc
, r
);
1301 Expression
*increment
= new CallExp(loc
, new DotIdExp(loc
, e
, idpopFront
));
1303 /* Declaration statement for e:
1304 * auto e = __r.idfront;
1306 e
= new VarExp(loc
, r
);
1307 Expression
*einit
= new DotIdExp(loc
, e
, idfront
);
1308 Statement
*makeargs
, *forbody
;
1311 Parameter
*p
= (*fs
->parameters
)[0];
1312 VarDeclaration
*ve
= new VarDeclaration(loc
, p
->type
, p
->ident
, new ExpInitializer(loc
, einit
));
1313 ve
->storage_class
|= STCforeach
;
1314 ve
->storage_class
|= p
->storageClass
& (STCin
| STCout
| STCref
| STC_TYPECTOR
);
1316 makeargs
= new ExpStatement(loc
, ve
);
1320 VarDeclaration
*vd
= copyToTemp(STCref
, "__front", einit
);
1321 dsymbolSemantic(vd
, sc
);
1322 makeargs
= new ExpStatement(loc
, vd
);
1324 Type
*tfront
= NULL
;
1325 if (FuncDeclaration
*fd
= sfront
->isFuncDeclaration())
1327 if (!fd
->functionSemantic())
1331 else if (TemplateDeclaration
*td
= sfront
->isTemplateDeclaration())
1334 if (FuncDeclaration
*f
= resolveFuncCall(loc
, sc
, td
, NULL
, tab
, &a
, 1))
1337 else if (Declaration
*d
= sfront
->isDeclaration())
1341 if (!tfront
|| tfront
->ty
== Terror
)
1344 if (tfront
->toBasetype()->ty
== Tfunction
)
1345 tfront
= tfront
->toBasetype()->nextOf();
1346 if (tfront
->ty
== Tvoid
)
1348 fs
->error("%s.front is void and has no value", oaggr
->toChars());
1352 // Resolve inout qualifier of front type
1353 tfront
= tfront
->substWildTo(tab
->mod
);
1355 Expression
*ve
= new VarExp(loc
, vd
);
1358 Expressions
*exps
= new Expressions();
1361 while (exps
->length
< dim
)
1363 pos
= expandAliasThisTuples(exps
, pos
);
1367 if (exps
->length
!= dim
)
1369 const char *plural
= exps
->length
> 1 ? "s" : "";
1370 fs
->error("cannot infer argument types, expected %d argument%s, not %d",
1371 exps
->length
, plural
, dim
);
1375 for (size_t i
= 0; i
< dim
; i
++)
1377 Parameter
*p
= (*fs
->parameters
)[i
];
1378 Expression
*exp
= (*exps
)[i
];
1380 p
->type
= exp
->type
;
1381 p
->type
= typeSemantic(p
->type
->addStorageClass(p
->storageClass
), loc
, sc2
);
1382 if (!exp
->implicitConvTo(p
->type
))
1385 VarDeclaration
*var
= new VarDeclaration(loc
, p
->type
, p
->ident
, new ExpInitializer(loc
, exp
));
1386 var
->storage_class
|= STCctfe
| STCref
| STCforeach
;
1387 makeargs
= new CompoundStatement(loc
, makeargs
, new ExpStatement(loc
, var
));
1392 forbody
= new CompoundStatement(loc
,
1393 makeargs
, fs
->_body
);
1395 s
= new ForStatement(loc
, init
, condition
, increment
, forbody
, fs
->endloc
);
1396 if (LabelStatement
*ls
= checkLabeledLoop(sc
, fs
))
1398 s
= statementSemantic(s
, sc2
);
1402 fs
->error("cannot infer argument types");
1406 if (fs
->op
== TOKforeach_reverse
)
1407 fs
->deprecation("cannot use foreach_reverse with a delegate");
1410 if (fs
->checkForArgTypes())
1412 fs
->_body
= semanticNoScope(fs
->_body
, sc2
);
1417 TypeFunction
*tfld
= NULL
;
1420 FuncDeclaration
*fdapply
= sapply
->isFuncDeclaration();
1423 assert(fdapply
->type
&& fdapply
->type
->ty
== Tfunction
);
1424 tfld
= (TypeFunction
*)typeSemantic(fdapply
->type
, loc
, sc2
);
1427 else if (tab
->ty
== Tdelegate
)
1429 tfld
= (TypeFunction
*)tab
->nextOf();
1431 //printf("tfld = %s\n", tfld->toChars());
1432 if (tfld
->parameterList
.parameters
->length
== 1)
1434 Parameter
*p
= tfld
->parameterList
[0];
1435 if (p
->type
&& p
->type
->ty
== Tdelegate
)
1437 Type
*t
= typeSemantic(p
->type
, loc
, sc2
);
1438 assert(t
->ty
== Tdelegate
);
1439 tfld
= (TypeFunction
*)t
->nextOf();
1445 /* Turn body into the function literal:
1446 * int delegate(ref T param) { body }
1448 Parameters
*params
= new Parameters();
1449 for (size_t i
= 0; i
< dim
; i
++)
1451 Parameter
*p
= (*fs
->parameters
)[i
];
1452 StorageClass stc
= STCref
;
1455 p
->type
= typeSemantic(p
->type
, loc
, sc2
);
1456 p
->type
= p
->type
->addStorageClass(p
->storageClass
);
1459 Parameter
*prm
= tfld
->parameterList
[i
];
1460 //printf("\tprm = %s%s\n", (prm->storageClass&STCref?"ref ":""), prm->ident->toChars());
1461 stc
= prm
->storageClass
& STCref
;
1462 id
= p
->ident
; // argument copy is not need.
1463 if ((p
->storageClass
& STCref
) != stc
)
1467 fs
->error("foreach: cannot make %s ref", p
->ident
->toChars());
1473 else if (p
->storageClass
& STCref
)
1475 // default delegate parameters are marked as ref, then
1476 // argument copy is not need.
1481 // Make a copy of the ref argument so it isn't
1484 id
= Identifier::generateId("__applyArg", (int)i
);
1486 Initializer
*ie
= new ExpInitializer(Loc(), new IdentifierExp(Loc(), id
));
1487 VarDeclaration
*v
= new VarDeclaration(Loc(), p
->type
, p
->ident
, ie
);
1488 v
->storage_class
|= STCtemp
;
1489 s
= new ExpStatement(Loc(), v
);
1490 fs
->_body
= new CompoundStatement(loc
, s
, fs
->_body
);
1492 params
->push(new Parameter(stc
, p
->type
, id
, NULL
, NULL
));
1494 // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable.
1495 StorageClass stc
= mergeFuncAttrs(STCsafe
| STCpure
| STCnogc
, fs
->func
);
1496 tfld
= new TypeFunction(ParameterList(params
), Type::tint32
, LINKd
, stc
);
1497 fs
->cases
= new Statements();
1498 fs
->gotos
= new ScopeStatements();
1499 FuncLiteralDeclaration
*fld
= new FuncLiteralDeclaration(loc
, Loc(), tfld
, TOKdelegate
, fs
);
1500 fld
->fbody
= fs
->_body
;
1501 Expression
*flde
= new FuncExp(loc
, fld
);
1502 flde
= expressionSemantic(flde
, sc2
);
1503 fld
->tookAddressOf
= 0;
1505 // Resolve any forward referenced goto's
1506 for (size_t i
= 0; i
< fs
->gotos
->length
; i
++)
1508 GotoStatement
*gs
= (GotoStatement
*)(*fs
->gotos
)[i
]->statement
;
1509 if (!gs
->label
->statement
)
1511 // 'Promote' it to this scope, and replace with a return
1512 fs
->cases
->push(gs
);
1513 s
= new ReturnStatement(Loc(), new IntegerExp(fs
->cases
->length
+ 1));
1514 (*fs
->gotos
)[i
]->statement
= s
;
1518 Expression
*e
= NULL
;
1522 e
= new DeclarationExp(loc
, vinit
);
1523 e
= expressionSemantic(e
, sc2
);
1524 if (e
->op
== TOKerror
)
1531 Parameter
*p
= (*fs
->parameters
)[0];
1532 bool isRef
= (p
->storageClass
& STCref
) != 0;
1536 Type
*ti
= (isRef
? taa
->index
->addMod(MODconst
) : taa
->index
);
1537 if (isRef
? !ti
->constConv(ta
) : !ti
->implicitConvTo(ta
))
1539 fs
->error("foreach: index must be type %s, not %s", ti
->toChars(), ta
->toChars());
1542 p
= (*fs
->parameters
)[1];
1543 isRef
= (p
->storageClass
& STCref
) != 0;
1546 Type
*taav
= taa
->nextOf();
1547 if (isRef
? !taav
->constConv(ta
) : !taav
->implicitConvTo(ta
))
1549 fs
->error("foreach: value must be type %s, not %s", taav
->toChars(), ta
->toChars());
1554 * extern(C) int _aaApply(void*, in size_t, int delegate(void*))
1555 * _aaApply(aggr, keysize, flde)
1557 * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
1558 * _aaApply2(aggr, keysize, flde)
1560 static const char *name
[2] = { "_aaApply", "_aaApply2" };
1561 static FuncDeclaration
*fdapply
[2] = { NULL
, NULL
};
1562 static TypeDelegate
*fldeTy
[2] = { NULL
, NULL
};
1564 unsigned char i
= (dim
== 2 ? 1 : 0);
1567 params
= new Parameters();
1568 params
->push(new Parameter(0, Type::tvoid
->pointerTo(), NULL
, NULL
, NULL
));
1569 params
->push(new Parameter(STCin
, Type::tsize_t
, NULL
, NULL
, NULL
));
1570 Parameters
* dgparams
= new Parameters
;
1571 dgparams
->push(new Parameter(0, Type::tvoidptr
, NULL
, NULL
, NULL
));
1573 dgparams
->push(new Parameter(0, Type::tvoidptr
, NULL
, NULL
, NULL
));
1574 fldeTy
[i
] = new TypeDelegate(new TypeFunction(ParameterList(dgparams
),
1575 Type::tint32
, LINKd
));
1576 params
->push(new Parameter(0, fldeTy
[i
], NULL
, NULL
, NULL
));
1577 fdapply
[i
] = FuncDeclaration::genCfunc(params
, Type::tint32
, name
[i
]);
1580 Expressions
*exps
= new Expressions();
1581 exps
->push(fs
->aggr
);
1582 d_uns64 keysize
= taa
->index
->size();
1583 if (keysize
== SIZE_INVALID
)
1585 assert(keysize
< UINT64_MAX
- target
.ptrsize
);
1586 keysize
= (keysize
+ (target
.ptrsize
- 1)) & ~(target
.ptrsize
- 1);
1587 // paint delegate argument to the type runtime expects
1588 if (!fldeTy
[i
]->equals(flde
->type
))
1590 flde
= new CastExp(loc
, flde
, flde
->type
);
1591 flde
->type
= fldeTy
[i
];
1593 exps
->push(new IntegerExp(Loc(), keysize
, Type::tsize_t
));
1596 ec
= new VarExp(Loc(), fdapply
[i
], false);
1597 ec
= new CallExp(loc
, ec
, exps
);
1598 ec
->type
= Type::tint32
; // don't run semantic() on ec
1600 else if (tab
->ty
== Tarray
|| tab
->ty
== Tsarray
)
1603 * _aApply(aggr, flde)
1605 static const char fntab
[9][3] =
1610 const int BUFFER_LEN
= 7+1+2+ sizeof(dim
)*3 + 1;
1611 char fdname
[BUFFER_LEN
];
1616 case Tchar
: flag
= 0; break;
1617 case Twchar
: flag
= 3; break;
1618 case Tdchar
: flag
= 6; break;
1623 case Tchar
: flag
+= 0; break;
1624 case Twchar
: flag
+= 1; break;
1625 case Tdchar
: flag
+= 2; break;
1628 const char *r
= (fs
->op
== TOKforeach_reverse
) ? "R" : "";
1629 int j
= sprintf(fdname
, "_aApply%s%.*s%llu", r
, 2, fntab
[flag
], (ulonglong
)dim
);
1630 assert(j
< BUFFER_LEN
);
1632 FuncDeclaration
*fdapply
;
1634 params
= new Parameters();
1635 params
->push(new Parameter(STCin
, tn
->arrayOf(), NULL
, NULL
, NULL
));
1636 Parameters
* dgparams
= new Parameters
;
1637 dgparams
->push(new Parameter(0, Type::tvoidptr
, NULL
, NULL
, NULL
));
1639 dgparams
->push(new Parameter(0, Type::tvoidptr
, NULL
, NULL
, NULL
));
1640 dgty
= new TypeDelegate(new TypeFunction(ParameterList(dgparams
),
1641 Type::tint32
, LINKd
));
1642 params
->push(new Parameter(0, dgty
, NULL
, NULL
, NULL
));
1643 fdapply
= FuncDeclaration::genCfunc(params
, Type::tint32
, fdname
);
1645 if (tab
->ty
== Tsarray
)
1646 fs
->aggr
= fs
->aggr
->castTo(sc2
, tn
->arrayOf());
1648 // paint delegate argument to the type runtime expects
1649 if (!dgty
->equals(flde
->type
)) {
1650 flde
= new CastExp(loc
, flde
, flde
->type
);
1654 ec
= new VarExp(Loc(), fdapply
, false);
1655 ec
= new CallExp(loc
, ec
, fs
->aggr
, flde
);
1656 ec
->type
= Type::tint32
; // don't run semantic() on ec
1658 else if (tab
->ty
== Tdelegate
)
1663 if (fs
->aggr
->op
== TOKdelegate
&&
1664 ((DelegateExp
*)fs
->aggr
)->func
->isNested())
1666 // See Bugzilla 3560
1667 fs
->aggr
= ((DelegateExp
*)fs
->aggr
)->e1
;
1669 ec
= new CallExp(loc
, fs
->aggr
, flde
);
1670 ec
= expressionSemantic(ec
, sc2
);
1671 if (ec
->op
== TOKerror
)
1673 if (ec
->type
!= Type::tint32
)
1675 fs
->error("opApply() function for %s must return an int", tab
->toChars());
1681 if (global
.params
.vsafe
)
1682 fld
->tookAddressOf
= 1; // allocate a closure unless the opApply() uses 'scope'
1684 assert(tab
->ty
== Tstruct
|| tab
->ty
== Tclass
);
1689 ec
= new DotIdExp(loc
, fs
->aggr
, sapply
->ident
);
1690 ec
= new CallExp(loc
, ec
, flde
);
1691 ec
= expressionSemantic(ec
, sc2
);
1692 if (ec
->op
== TOKerror
)
1694 if (ec
->type
!= Type::tint32
)
1696 fs
->error("opApply() function for %s must return an int", tab
->toChars());
1700 e
= Expression::combine(e
, ec
);
1702 if (!fs
->cases
->length
)
1704 // Easy case, a clean exit from the loop
1705 e
= new CastExp(loc
, e
, Type::tvoid
); // Bugzilla 13899
1706 s
= new ExpStatement(loc
, e
);
1710 // Construct a switch statement around the return value
1711 // of the apply function.
1712 Statements
*a
= new Statements();
1714 // default: break; takes care of cases 0 and 1
1715 s
= new BreakStatement(Loc(), NULL
);
1716 s
= new DefaultStatement(Loc(), s
);
1720 for (size_t i
= 0; i
< fs
->cases
->length
; i
++)
1722 s
= (*fs
->cases
)[i
];
1723 s
= new CaseStatement(Loc(), new IntegerExp(i
+ 2), s
);
1727 s
= new CompoundStatement(loc
, a
);
1728 s
= new SwitchStatement(loc
, e
, s
, false);
1730 s
= statementSemantic(s
, sc2
);
1735 s
= new ErrorStatement();
1739 fs
->error("foreach: %s is not an aggregate type", fs
->aggr
->type
->toChars());
1747 void visit(ForeachRangeStatement
*fs
)
1749 //printf("ForeachRangeStatement::semantic() %p\n", fs);
1751 fs
->lwr
= expressionSemantic(fs
->lwr
, sc
);
1752 fs
->lwr
= resolveProperties(sc
, fs
->lwr
);
1753 fs
->lwr
= fs
->lwr
->optimize(WANTvalue
);
1756 fs
->error("invalid range lower bound %s", fs
->lwr
->toChars());
1761 fs
->upr
= expressionSemantic(fs
->upr
, sc
);
1762 fs
->upr
= resolveProperties(sc
, fs
->upr
);
1763 fs
->upr
= fs
->upr
->optimize(WANTvalue
);
1766 fs
->error("invalid range upper bound %s", fs
->upr
->toChars());
1772 fs
->prm
->type
= typeSemantic(fs
->prm
->type
, loc
, sc
);
1773 fs
->prm
->type
= fs
->prm
->type
->addStorageClass(fs
->prm
->storageClass
);
1774 fs
->lwr
= fs
->lwr
->implicitCastTo(sc
, fs
->prm
->type
);
1776 if (fs
->upr
->implicitConvTo(fs
->prm
->type
) || (fs
->prm
->storageClass
& STCref
))
1778 fs
->upr
= fs
->upr
->implicitCastTo(sc
, fs
->prm
->type
);
1782 // See if upr-1 fits in prm->type
1783 Expression
*limit
= new MinExp(loc
, fs
->upr
, new IntegerExp(1));
1784 limit
= expressionSemantic(limit
, sc
);
1785 limit
= limit
->optimize(WANTvalue
);
1786 if (!limit
->implicitConvTo(fs
->prm
->type
))
1788 fs
->upr
= fs
->upr
->implicitCastTo(sc
, fs
->prm
->type
);
1794 /* Must infer types from lwr and upr
1796 Type
*tlwr
= fs
->lwr
->type
->toBasetype();
1797 if (tlwr
->ty
== Tstruct
|| tlwr
->ty
== Tclass
)
1799 /* Just picking the first really isn't good enough.
1801 fs
->prm
->type
= fs
->lwr
->type
;
1803 else if (fs
->lwr
->type
== fs
->upr
->type
)
1805 /* Same logic as CondExp ?lwr:upr
1807 fs
->prm
->type
= fs
->lwr
->type
;
1811 AddExp
ea(loc
, fs
->lwr
, fs
->upr
);
1812 if (typeCombine(&ea
, sc
))
1814 fs
->prm
->type
= ea
.type
;
1818 fs
->prm
->type
= fs
->prm
->type
->addStorageClass(fs
->prm
->storageClass
);
1820 if (fs
->prm
->type
->ty
== Terror
||
1821 fs
->lwr
->op
== TOKerror
||
1822 fs
->upr
->op
== TOKerror
)
1827 /* Convert to a for loop:
1828 * foreach (key; lwr .. upr) =>
1829 * for (auto key = lwr, auto tmp = upr; key < tmp; ++key)
1831 * foreach_reverse (key; lwr .. upr) =>
1832 * for (auto tmp = lwr, auto key = upr; key-- > tmp;)
1834 ExpInitializer
*ie
= new ExpInitializer(loc
, (fs
->op
== TOKforeach
) ? fs
->lwr
: fs
->upr
);
1835 fs
->key
= new VarDeclaration(loc
, fs
->upr
->type
->mutableOf(), Identifier::generateId("__key"), ie
);
1836 fs
->key
->storage_class
|= STCtemp
;
1837 SignExtendedNumber lower
= getIntRange(fs
->lwr
).imin
;
1838 SignExtendedNumber upper
= getIntRange(fs
->upr
).imax
;
1841 fs
->key
->range
= new IntRange(lower
, upper
);
1844 Identifier
*id
= Identifier::generateId("__limit");
1845 ie
= new ExpInitializer(loc
, (fs
->op
== TOKforeach
) ? fs
->upr
: fs
->lwr
);
1846 VarDeclaration
*tmp
= new VarDeclaration(loc
, fs
->upr
->type
, id
, ie
);
1847 tmp
->storage_class
|= STCtemp
;
1849 Statements
*cs
= new Statements();
1850 // Keep order of evaluation as lwr, then upr
1851 if (fs
->op
== TOKforeach
)
1853 cs
->push(new ExpStatement(loc
, fs
->key
));
1854 cs
->push(new ExpStatement(loc
, tmp
));
1858 cs
->push(new ExpStatement(loc
, tmp
));
1859 cs
->push(new ExpStatement(loc
, fs
->key
));
1861 Statement
*forinit
= new CompoundDeclarationStatement(loc
, cs
);
1864 if (fs
->op
== TOKforeach_reverse
)
1866 cond
= new PostExp(TOKminusminus
, loc
, new VarExp(loc
, fs
->key
));
1867 if (fs
->prm
->type
->isscalar())
1870 cond
= new CmpExp(TOKgt
, loc
, cond
, new VarExp(loc
, tmp
));
1875 cond
= new EqualExp(TOKnotequal
, loc
, cond
, new VarExp(loc
, tmp
));
1880 if (fs
->prm
->type
->isscalar())
1883 cond
= new CmpExp(TOKlt
, loc
, new VarExp(loc
, fs
->key
), new VarExp(loc
, tmp
));
1888 cond
= new EqualExp(TOKnotequal
, loc
, new VarExp(loc
, fs
->key
), new VarExp(loc
, tmp
));
1892 Expression
*increment
= NULL
;
1893 if (fs
->op
== TOKforeach
)
1896 //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
1897 increment
= new PreExp(TOKpreplusplus
, loc
, new VarExp(loc
, fs
->key
));
1900 if ((fs
->prm
->storageClass
& STCref
) && fs
->prm
->type
->equals(fs
->key
->type
))
1902 fs
->key
->range
= NULL
;
1903 AliasDeclaration
*v
= new AliasDeclaration(loc
, fs
->prm
->ident
, fs
->key
);
1904 fs
->_body
= new CompoundStatement(loc
, new ExpStatement(loc
, v
), fs
->_body
);
1908 ie
= new ExpInitializer(loc
, new CastExp(loc
, new VarExp(loc
, fs
->key
), fs
->prm
->type
));
1909 VarDeclaration
*v
= new VarDeclaration(loc
, fs
->prm
->type
, fs
->prm
->ident
, ie
);
1910 v
->storage_class
|= STCtemp
| STCforeach
| (fs
->prm
->storageClass
& STCref
);
1911 fs
->_body
= new CompoundStatement(loc
, new ExpStatement(loc
, v
), fs
->_body
);
1912 if (fs
->key
->range
&& !fs
->prm
->type
->isMutable())
1914 /* Limit the range of the key to the specified range
1916 v
->range
= new IntRange(fs
->key
->range
->imin
, fs
->key
->range
->imax
- SignExtendedNumber(1));
1919 if (fs
->prm
->storageClass
& STCref
)
1921 if (fs
->key
->type
->constConv(fs
->prm
->type
) <= MATCHnomatch
)
1923 fs
->error("prmument type mismatch, %s to ref %s",
1924 fs
->key
->type
->toChars(), fs
->prm
->type
->toChars());
1929 ForStatement
*s
= new ForStatement(loc
, forinit
, cond
, increment
, fs
->_body
, fs
->endloc
);
1930 if (LabelStatement
*ls
= checkLabeledLoop(sc
, fs
))
1932 result
= statementSemantic(s
, sc
);
1935 void visit(IfStatement
*ifs
)
1937 // Evaluate at runtime
1938 unsigned cs0
= sc
->callSuper
;
1940 unsigned *fi0
= sc
->saveFieldInit();
1941 unsigned *fi1
= NULL
;
1943 // check in syntax level
1944 ifs
->condition
= checkAssignmentAsCondition(ifs
->condition
);
1946 ScopeDsymbol
*sym
= new ScopeDsymbol();
1947 sym
->parent
= sc
->scopesym
;
1948 sym
->endlinnum
= ifs
->endloc
.linnum
;
1949 Scope
*scd
= sc
->push(sym
);
1952 /* Declare prm, which we will set to be the
1953 * result of condition.
1955 ExpInitializer
*ei
= new ExpInitializer(ifs
->loc
, ifs
->condition
);
1956 ifs
->match
= new VarDeclaration(ifs
->loc
, ifs
->prm
->type
, ifs
->prm
->ident
, ei
);
1957 ifs
->match
->parent
= sc
->func
;
1958 ifs
->match
->storage_class
|= ifs
->prm
->storageClass
;
1959 dsymbolSemantic(ifs
->match
, scd
);
1961 DeclarationExp
*de
= new DeclarationExp(ifs
->loc
, ifs
->match
);
1962 VarExp
*ve
= new VarExp(ifs
->loc
, ifs
->match
);
1963 ifs
->condition
= new CommaExp(ifs
->loc
, de
, ve
);
1964 ifs
->condition
= expressionSemantic(ifs
->condition
, scd
);
1966 if (ifs
->match
->edtor
)
1968 Statement
*sdtor
= new DtorExpStatement(ifs
->loc
, ifs
->match
->edtor
, ifs
->match
);
1969 sdtor
= new ScopeGuardStatement(ifs
->loc
, TOKon_scope_exit
, sdtor
);
1970 ifs
->ifbody
= new CompoundStatement(ifs
->loc
, sdtor
, ifs
->ifbody
);
1971 ifs
->match
->storage_class
|= STCnodtor
;
1976 if (ifs
->condition
->op
== TOKdotid
)
1977 ((DotIdExp
*)ifs
->condition
)->noderef
= true;
1979 ifs
->condition
= expressionSemantic(ifs
->condition
, sc
);
1980 ifs
->condition
= resolveProperties(sc
, ifs
->condition
);
1981 ifs
->condition
= ifs
->condition
->addDtorHook(sc
);
1983 if (checkNonAssignmentArrayOp(ifs
->condition
))
1984 ifs
->condition
= new ErrorExp();
1985 ifs
->condition
= checkGC(sc
, ifs
->condition
);
1987 // Convert to boolean after declaring prm so this works:
1988 // if (S prm = S()) {}
1989 // where S is a struct that defines opCast!bool.
1990 ifs
->condition
= ifs
->condition
->toBoolean(sc
);
1992 // If we can short-circuit evaluate the if statement, don't do the
1993 // semantic analysis of the skipped code.
1994 // This feature allows a limited form of conditional compilation.
1995 ifs
->condition
= ifs
->condition
->optimize(WANTvalue
);
1996 ifs
->ifbody
= semanticNoScope(ifs
->ifbody
, scd
);
1999 cs1
= sc
->callSuper
;
2000 fi1
= sc
->fieldinit
;
2001 sc
->callSuper
= cs0
;
2002 sc
->fieldinit
= fi0
;
2004 ifs
->elsebody
= semanticScope(ifs
->elsebody
, sc
, NULL
, NULL
);
2005 sc
->mergeCallSuper(ifs
->loc
, cs1
);
2006 sc
->mergeFieldInit(ifs
->loc
, fi1
);
2008 if (ifs
->condition
->op
== TOKerror
||
2009 (ifs
->ifbody
&& ifs
->ifbody
->isErrorStatement()) ||
2010 (ifs
->elsebody
&& ifs
->elsebody
->isErrorStatement()))
2017 void visit(ConditionalStatement
*cs
)
2019 //printf("ConditionalStatement::semantic()\n");
2021 // If we can short-circuit evaluate the if statement, don't do the
2022 // semantic analysis of the skipped code.
2023 // This feature allows a limited form of conditional compilation.
2024 if (cs
->condition
->include(sc
))
2026 DebugCondition
*dc
= cs
->condition
->isDebugCondition();
2030 sc
->flags
|= SCOPEdebug
;
2031 cs
->ifbody
= statementSemantic(cs
->ifbody
, sc
);
2035 cs
->ifbody
= statementSemantic(cs
->ifbody
, sc
);
2036 result
= cs
->ifbody
;
2041 cs
->elsebody
= statementSemantic(cs
->elsebody
, sc
);
2042 result
= cs
->elsebody
;
2046 void visit(PragmaStatement
*ps
)
2048 // Should be merged with PragmaDeclaration
2049 //printf("PragmaStatement::semantic() %s\n", ps->toChars());
2050 //printf("body = %p\n", ps->_body);
2051 if (ps
->ident
== Id::msg
)
2055 for (size_t i
= 0; i
< ps
->args
->length
; i
++)
2057 Expression
*e
= (*ps
->args
)[i
];
2059 sc
= sc
->startCTFE();
2060 e
= expressionSemantic(e
, sc
);
2061 e
= resolveProperties(sc
, e
);
2063 // pragma(msg) is allowed to contain types as well as expressions
2064 e
= ctfeInterpretForPragmaMsg(e
);
2065 if (e
->op
== TOKerror
)
2067 errorSupplemental(ps
->loc
, "while evaluating pragma(msg, %s)", (*ps
->args
)[i
]->toChars());
2070 StringExp
*se
= e
->toStringExp();
2073 se
= se
->toUTF8(sc
);
2074 fprintf(stderr
, "%.*s", (int)se
->len
, (char *)se
->string
);
2077 fprintf(stderr
, "%s", e
->toChars());
2079 fprintf(stderr
, "\n");
2082 else if (ps
->ident
== Id::lib
)
2084 /* Should this be allowed?
2086 ps
->error("pragma(lib) not allowed as statement");
2089 else if (ps
->ident
== Id::startaddress
)
2091 if (!ps
->args
|| ps
->args
->length
!= 1)
2092 ps
->error("function name expected for start address");
2095 Expression
*e
= (*ps
->args
)[0];
2097 sc
= sc
->startCTFE();
2098 e
= expressionSemantic(e
, sc
);
2099 e
= resolveProperties(sc
, e
);
2102 e
= e
->ctfeInterpret();
2104 Dsymbol
*sa
= getDsymbol(e
);
2105 if (!sa
|| !sa
->isFuncDeclaration())
2107 ps
->error("function name expected for start address, not `%s`", e
->toChars());
2112 ps
->_body
= statementSemantic(ps
->_body
, sc
);
2113 if (ps
->_body
->isErrorStatement())
2123 else if (ps
->ident
== Id::Pinline
)
2125 PINLINE inlining
= PINLINEdefault
;
2126 if (!ps
->args
|| ps
->args
->length
== 0)
2127 inlining
= PINLINEdefault
;
2128 else if (!ps
->args
|| ps
->args
->length
!= 1)
2130 ps
->error("boolean expression expected for pragma(inline)");
2135 Expression
*e
= (*ps
->args
)[0];
2137 if (e
->op
!= TOKint64
|| !e
->type
->equals(Type::tbool
))
2139 ps
->error("pragma(inline, true or false) expected, not %s", e
->toChars());
2143 if (e
->isBool(true))
2144 inlining
= PINLINEalways
;
2145 else if (e
->isBool(false))
2146 inlining
= PINLINEnever
;
2148 FuncDeclaration
*fd
= sc
->func
;
2151 ps
->error("pragma(inline) is not inside a function");
2154 fd
->inlining
= inlining
;
2159 ps
->error("unrecognized pragma(%s)", ps
->ident
->toChars());
2165 if (ps
->ident
== Id::msg
|| ps
->ident
== Id::startaddress
)
2167 ps
->error("`pragma(%s)` is missing a terminating `;`", ps
->ident
->toChars());
2170 ps
->_body
= statementSemantic(ps
->_body
, sc
);
2179 void visit(StaticAssertStatement
*s
)
2181 semantic2(s
->sa
, sc
);
2184 void visit(SwitchStatement
*ss
)
2186 //printf("SwitchStatement::semantic(%p)\n", ss);
2190 result
= ss
; // already run
2193 bool conditionError
= false;
2194 ss
->condition
= expressionSemantic(ss
->condition
, sc
);
2195 ss
->condition
= resolveProperties(sc
, ss
->condition
);
2198 TypeEnum
*te
= NULL
;
2199 while (ss
->condition
->op
!= TOKerror
)
2201 // preserve enum type for final switches
2202 if (ss
->condition
->type
->ty
== Tenum
)
2203 te
= (TypeEnum
*)ss
->condition
->type
;
2204 if (ss
->condition
->type
->isString())
2206 // If it's not an array, cast it to one
2207 if (ss
->condition
->type
->ty
!= Tarray
)
2209 ss
->condition
= ss
->condition
->implicitCastTo(sc
, ss
->condition
->type
->nextOf()->arrayOf());
2211 ss
->condition
->type
= ss
->condition
->type
->constOf();
2214 ss
->condition
= integralPromotions(ss
->condition
, sc
);
2215 if (ss
->condition
->op
!= TOKerror
&& ss
->condition
->type
->isintegral())
2218 AggregateDeclaration
*ad
= isAggregate(ss
->condition
->type
);
2219 if (ad
&& ad
->aliasthis
&& ss
->condition
->type
!= att
)
2221 if (!att
&& ss
->condition
->type
->checkAliasThisRec())
2222 att
= ss
->condition
->type
;
2223 if (Expression
*e
= resolveAliasThis(sc
, ss
->condition
, true))
2230 if (ss
->condition
->op
!= TOKerror
)
2232 ss
->error("`%s` must be of integral or string type, it is a %s",
2233 ss
->condition
->toChars(), ss
->condition
->type
->toChars());
2234 conditionError
= true;
2238 if (checkNonAssignmentArrayOp(ss
->condition
))
2239 ss
->condition
= new ErrorExp();
2240 ss
->condition
= ss
->condition
->optimize(WANTvalue
);
2241 ss
->condition
= checkGC(sc
, ss
->condition
);
2242 if (ss
->condition
->op
== TOKerror
)
2243 conditionError
= true;
2245 bool needswitcherror
= false;
2247 ss
->lastVar
= sc
->lastVar
;
2253 ss
->cases
= new CaseStatements();
2254 sc
->noctor
++; // BUG: should use Scope::mergeCallSuper() for each case instead
2255 ss
->_body
= statementSemantic(ss
->_body
, sc
);
2258 if (conditionError
|| (ss
->_body
&& ss
->_body
->isErrorStatement()))
2261 // Resolve any goto case's with exp
2262 for (size_t i
= 0; i
< ss
->gotoCases
.length
; i
++)
2264 GotoCaseStatement
*gcs
= ss
->gotoCases
[i
];
2268 gcs
->error("no case statement following goto case;");
2272 for (Scope
*scx
= sc
; scx
; scx
= scx
->enclosing
)
2276 for (size_t j
= 0; j
< scx
->sw
->cases
->length
; j
++)
2278 CaseStatement
*cs
= (*scx
->sw
->cases
)[j
];
2280 if (cs
->exp
->equals(gcs
->exp
))
2287 gcs
->error("case %s not found", gcs
->exp
->toChars());
2296 Type
*t
= ss
->condition
->type
;
2298 EnumDeclaration
*ed
= NULL
;
2299 if (t
&& ((ds
= t
->toDsymbol(sc
)) != NULL
))
2300 ed
= ds
->isEnumDeclaration(); // typedef'ed enum
2301 if (!ed
&& te
&& ((ds
= te
->toDsymbol(sc
)) != NULL
))
2302 ed
= ds
->isEnumDeclaration();
2305 size_t dim
= ed
->members
->length
;
2306 for (size_t i
= 0; i
< dim
; i
++)
2308 EnumMember
*em
= (*ed
->members
)[i
]->isEnumMember();
2311 for (size_t j
= 0; j
< ss
->cases
->length
; j
++)
2313 CaseStatement
*cs
= (*ss
->cases
)[j
];
2314 if (cs
->exp
->equals(em
->value()) ||
2315 (!cs
->exp
->type
->isString() && !em
->value()->type
->isString() &&
2316 cs
->exp
->toInteger() == em
->value()->toInteger()))
2319 ss
->error("enum member %s not represented in final switch", em
->toChars());
2327 needswitcherror
= true;
2330 if (!sc
->sw
->sdefault
&& (!ss
->isFinal
|| needswitcherror
|| global
.params
.useAssert
== CHECKENABLEon
))
2332 ss
->hasNoDefault
= 1;
2334 if (!ss
->isFinal
&& (!ss
->_body
|| !ss
->_body
->isErrorStatement()))
2335 ss
->error("switch statement without a default; use `final switch` or add `default: assert(0);` or add `default: break;`");
2337 // Generate runtime error if the default is hit
2338 Statements
*a
= new Statements();
2339 CompoundStatement
*cs
;
2342 if (global
.params
.useSwitchError
== CHECKENABLEon
&&
2343 global
.params
.checkAction
!= CHECKACTION_halt
)
2345 if (global
.params
.checkAction
== CHECKACTION_C
)
2347 /* Rewrite as an assert(0) and let e2ir generate
2348 * the call to the C assert failure function
2350 s
= new ExpStatement(ss
->loc
, new AssertExp(ss
->loc
, new IntegerExp(ss
->loc
, 0, Type::tint32
)));
2353 s
= new SwitchErrorStatement(ss
->loc
);
2356 s
= new ExpStatement(ss
->loc
, new HaltExp(ss
->loc
));
2359 sc
->sw
->sdefault
= new DefaultStatement(ss
->loc
, s
);
2361 if (blockExit(ss
->_body
, sc
->func
, false) & BEfallthru
)
2362 a
->push(new BreakStatement(Loc(), NULL
));
2363 a
->push(sc
->sw
->sdefault
);
2364 cs
= new CompoundStatement(ss
->loc
, a
);
2368 if (ss
->checkLabel())
2377 result
= new ErrorStatement();
2380 void visit(CaseStatement
*cs
)
2382 SwitchStatement
*sw
= sc
->sw
;
2383 bool errors
= false;
2385 //printf("CaseStatement::semantic() %s\n", cs->toChars());
2386 sc
= sc
->startCTFE();
2387 cs
->exp
= expressionSemantic(cs
->exp
, sc
);
2388 cs
->exp
= resolveProperties(sc
, cs
->exp
);
2392 cs
->exp
= cs
->exp
->implicitCastTo(sc
, sw
->condition
->type
);
2393 cs
->exp
= cs
->exp
->optimize(WANTvalue
| WANTexpand
);
2395 Expression
*e
= cs
->exp
;
2396 // Remove all the casts the user and/or implicitCastTo may introduce
2397 // otherwise we'd sometimes fail the check below.
2398 while (e
->op
== TOKcast
)
2399 e
= ((CastExp
*)e
)->e1
;
2401 /* This is where variables are allowed as case expressions.
2403 if (e
->op
== TOKvar
)
2405 VarExp
*ve
= (VarExp
*)e
;
2406 VarDeclaration
*v
= ve
->var
->isVarDeclaration();
2407 Type
*t
= cs
->exp
->type
->toBasetype();
2408 if (v
&& (t
->isintegral() || t
->ty
== Tclass
))
2410 /* Flag that we need to do special code generation
2411 * for this, i.e. generate a sequence of if-then-else
2415 /* TODO check if v can be uninitialized at that point.
2417 if (!v
->isConst() && !v
->isImmutable())
2419 cs
->deprecation("case variables have to be const or immutable");
2424 cs
->error("case variables not allowed in final switch statements");
2428 /* Also check if the VarExp is declared in a scope outside of this one.
2429 * 'scx' is set to the scope of the switch statement.
2431 for (Scope
*scx
= sc
; scx
; scx
= scx
->enclosing
)
2433 if (scx
->enclosing
&& scx
->enclosing
->sw
== sw
)
2435 assert(scx
->sw
== sw
);
2437 if (!scx
->search(cs
->exp
->loc
, v
->ident
, NULL
))
2439 cs
->error("case variable `%s` declared at %s cannot be declared in switch body",
2440 v
->toChars(), v
->loc
.toChars());
2449 cs
->exp
= cs
->exp
->ctfeInterpret();
2451 if (StringExp
*se
= cs
->exp
->toStringExp())
2453 else if (cs
->exp
->op
!= TOKint64
&& cs
->exp
->op
!= TOKerror
)
2455 cs
->error("case must be a string or an integral constant, not %s", cs
->exp
->toChars());
2460 for (size_t i
= 0; i
< sw
->cases
->length
; i
++)
2462 CaseStatement
*cs2
= (*sw
->cases
)[i
];
2464 //printf("comparing '%s' with '%s'\n", cs->exp->toChars(), cs2->exp->toChars());
2465 if (cs2
->exp
->equals(cs
->exp
))
2467 cs
->error("duplicate case %s in switch statement", cs
->exp
->toChars());
2473 sw
->cases
->push(cs
);
2475 // Resolve any goto case's with no exp to this case statement
2476 for (size_t i
= 0; i
< sw
->gotoCases
.length
; )
2478 GotoCaseStatement
*gcs
= sw
->gotoCases
[i
];
2483 sw
->gotoCases
.remove(i
); // remove from array
2489 if (sc
->sw
->tf
!= sc
->tf
)
2491 cs
->error("switch and case are in different finally blocks");
2497 cs
->error("case not in switch statement");
2500 cs
->statement
= statementSemantic(cs
->statement
, sc
);
2501 if (cs
->statement
->isErrorStatement())
2503 result
= cs
->statement
;
2506 if (errors
|| cs
->exp
->op
== TOKerror
)
2509 cs
->lastVar
= sc
->lastVar
;
2513 void visit(CaseRangeStatement
*crs
)
2515 SwitchStatement
*sw
= sc
->sw
;
2518 crs
->error("case range not in switch statement");
2522 //printf("CaseRangeStatement::semantic() %s\n", toChars());
2523 bool errors
= false;
2526 crs
->error("case ranges not allowed in final switch");
2530 sc
= sc
->startCTFE();
2531 crs
->first
= expressionSemantic(crs
->first
, sc
);
2532 crs
->first
= resolveProperties(sc
, crs
->first
);
2534 crs
->first
= crs
->first
->implicitCastTo(sc
, sw
->condition
->type
);
2535 crs
->first
= crs
->first
->ctfeInterpret();
2537 sc
= sc
->startCTFE();
2538 crs
->last
= expressionSemantic(crs
->last
, sc
);
2539 crs
->last
= resolveProperties(sc
, crs
->last
);
2541 crs
->last
= crs
->last
->implicitCastTo(sc
, sw
->condition
->type
);
2542 crs
->last
= crs
->last
->ctfeInterpret();
2544 if (crs
->first
->op
== TOKerror
|| crs
->last
->op
== TOKerror
|| errors
)
2547 statementSemantic(crs
->statement
, sc
);
2551 uinteger_t fval
= crs
->first
->toInteger();
2552 uinteger_t lval
= crs
->last
->toInteger();
2555 if ( (crs
->first
->type
->isunsigned() && fval
> lval
) ||
2556 (!crs
->first
->type
->isunsigned() && (sinteger_t
)fval
> (sinteger_t
)lval
))
2558 crs
->error("first case %s is greater than last case %s",
2559 crs
->first
->toChars(), crs
->last
->toChars());
2564 if (lval
- fval
> 256)
2566 crs
->error("had %llu cases which is more than 256 cases in case range", lval
- fval
);
2574 /* This works by replacing the CaseRange with an array of Case's.
2576 * case a: .. case b: s;
2584 Statements
*statements
= new Statements();
2585 for (uinteger_t i
= fval
; i
!= lval
+ 1; i
++)
2587 Statement
*s
= crs
->statement
;
2588 if (i
!= lval
) // if not last case
2589 s
= new ExpStatement(crs
->loc
, (Expression
*)NULL
);
2590 Expression
*e
= new IntegerExp(crs
->loc
, i
, crs
->first
->type
);
2591 Statement
*cs
= new CaseStatement(crs
->loc
, e
, s
);
2592 statements
->push(cs
);
2594 Statement
*s
= new CompoundStatement(crs
->loc
, statements
);
2595 s
= statementSemantic(s
, sc
);
2599 void visit(DefaultStatement
*ds
)
2601 //printf("DefaultStatement::semantic()\n");
2602 bool errors
= false;
2605 if (sc
->sw
->sdefault
)
2607 ds
->error("switch statement already has a default");
2610 sc
->sw
->sdefault
= ds
;
2612 if (sc
->sw
->tf
!= sc
->tf
)
2614 ds
->error("switch and default are in different finally blocks");
2617 if (sc
->sw
->isFinal
)
2619 ds
->error("default statement not allowed in final switch statement");
2625 ds
->error("default not in switch statement");
2628 ds
->statement
= statementSemantic(ds
->statement
, sc
);
2629 if (errors
|| ds
->statement
->isErrorStatement())
2632 ds
->lastVar
= sc
->lastVar
;
2636 void visit(GotoDefaultStatement
*gds
)
2641 gds
->error("goto default not in switch statement");
2644 if (gds
->sw
->isFinal
)
2646 gds
->error("goto default not allowed in final switch statement");
2652 void visit(GotoCaseStatement
*gcs
)
2656 gcs
->error("goto case not in switch statement");
2662 gcs
->exp
= expressionSemantic(gcs
->exp
, sc
);
2663 gcs
->exp
= gcs
->exp
->implicitCastTo(sc
, sc
->sw
->condition
->type
);
2664 gcs
->exp
= gcs
->exp
->optimize(WANTvalue
);
2665 if (gcs
->exp
->op
== TOKerror
)
2669 sc
->sw
->gotoCases
.push(gcs
);
2673 void visit(ReturnStatement
*rs
)
2675 //printf("ReturnStatement::semantic() %s\n", toChars());
2677 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
2680 fd
= fd
->fes
->func
; // fd is now function enclosing foreach
2682 TypeFunction
*tf
= (TypeFunction
*)fd
->type
;
2683 assert(tf
->ty
== Tfunction
);
2685 if (rs
->exp
&& rs
->exp
->op
== TOKvar
&& ((VarExp
*)rs
->exp
)->var
== fd
->vresult
)
2690 assert(rs
->caseDim
== 0);
2691 sc
->fes
->cases
->push(rs
);
2692 result
= new ReturnStatement(Loc(), new IntegerExp(sc
->fes
->cases
->length
+ 1));
2695 if (fd
->returnLabel
)
2697 GotoStatement
*gs
= new GotoStatement(rs
->loc
, Id::returnLabel
);
2698 gs
->label
= fd
->returnLabel
;
2704 fd
->returns
= new ReturnStatements();
2705 fd
->returns
->push(rs
);
2710 Type
*tret
= tf
->next
;
2711 Type
*tbret
= tret
? tret
->toBasetype() : NULL
;
2713 bool inferRef
= (tf
->isref
&& (fd
->storage_class
& STCauto
));
2714 Expression
*e0
= NULL
;
2716 bool errors
= false;
2717 if (sc
->flags
& SCOPEcontract
)
2719 rs
->error("return statements cannot be in contracts");
2722 if (sc
->os
&& sc
->os
->tok
!= TOKon_scope_failure
)
2724 rs
->error("return statements cannot be in %s bodies", Token::toChars(sc
->os
->tok
));
2729 rs
->error("return statements cannot be in finally bodies");
2733 if (fd
->isCtorDeclaration())
2737 rs
->error("cannot return expression from constructor");
2741 // Constructors implicitly do:
2743 rs
->exp
= new ThisExp(Loc());
2744 rs
->exp
->type
= tret
;
2748 fd
->hasReturnExp
|= (fd
->hasReturnExp
& 1 ? 16 : 1);
2750 FuncLiteralDeclaration
*fld
= fd
->isFuncLiteralDeclaration();
2752 rs
->exp
= inferType(rs
->exp
, tret
);
2753 else if (fld
&& fld
->treq
)
2754 rs
->exp
= inferType(rs
->exp
, fld
->treq
->nextOf()->nextOf());
2755 rs
->exp
= expressionSemantic(rs
->exp
, sc
);
2757 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
2758 if (rs
->exp
->op
== TOKtype
)
2759 rs
->exp
= resolveAliasThis(sc
, rs
->exp
);
2761 rs
->exp
= resolveProperties(sc
, rs
->exp
);
2762 if (rs
->exp
->checkType())
2763 rs
->exp
= new ErrorExp();
2764 if (FuncDeclaration
*f
= isFuncAddress(rs
->exp
))
2766 if (fd
->inferRetType
&& f
->checkForwardRef(rs
->exp
->loc
))
2767 rs
->exp
= new ErrorExp();
2769 if (checkNonAssignmentArrayOp(rs
->exp
))
2770 rs
->exp
= new ErrorExp();
2772 // Extract side-effect part
2773 rs
->exp
= Expression::extractLast(rs
->exp
, &e0
);
2774 if (rs
->exp
->op
== TOKcall
)
2775 rs
->exp
= valueNoDtor(rs
->exp
);
2778 e0
= e0
->optimize(WANTvalue
);
2780 /* Void-return function can have void typed expression
2781 * on return statement.
2783 if ((tbret
&& tbret
->ty
== Tvoid
) || rs
->exp
->type
->ty
== Tvoid
)
2785 if (rs
->exp
->type
->ty
!= Tvoid
)
2787 rs
->error("cannot return non-void from void function");
2790 rs
->exp
= new CastExp(rs
->loc
, rs
->exp
, Type::tvoid
);
2791 rs
->exp
= expressionSemantic(rs
->exp
, sc
);
2799 e0
= Expression::combine(e0
, rs
->exp
);
2803 e0
= checkGC(sc
, e0
);
2808 if (fd
->inferRetType
) // infer return type
2812 tf
->next
= rs
->exp
->type
;
2814 else if (tret
->ty
!= Terror
&& !rs
->exp
->type
->equals(tret
))
2816 int m1
= rs
->exp
->type
->implicitConvTo(tret
);
2817 int m2
= tret
->implicitConvTo(rs
->exp
->type
);
2818 //printf("exp->type = %s m2<-->m1 tret %s\n", rs->exp->type->toChars(), tret->toChars());
2819 //printf("m1 = %d, m2 = %d\n", m1, m2);
2824 tf
->next
= rs
->exp
->type
;
2827 else if (rs
->exp
->op
!= TOKerror
)
2829 rs
->error("mismatched function return type inference of %s and %s",
2830 rs
->exp
->type
->toChars(), tret
->toChars());
2832 tf
->next
= Type::terror
;
2837 tbret
= tret
->toBasetype();
2840 if (inferRef
) // deduce 'auto ref'
2842 /* Determine "refness" of function return:
2843 * if it's an lvalue, return by ref, else return by value
2845 if (rs
->exp
->isLvalue())
2847 /* May return by ref
2849 if (checkReturnEscapeRef(sc
, rs
->exp
, true))
2850 tf
->isref
= false; // return by value
2853 tf
->isref
= false; // return by value
2855 /* The "refness" is determined by all of return statements.
2857 * return 3; return x; // ok, x can be a value
2858 * return x; return 3; // ok, x can be a value
2864 // infer return type
2865 if (fd
->inferRetType
)
2867 if (tf
->next
&& tf
->next
->ty
!= Tvoid
)
2869 if (tf
->next
->ty
!= Terror
)
2871 rs
->error("mismatched function return type inference of void and %s",
2872 tf
->next
->toChars());
2875 tf
->next
= Type::terror
;
2878 tf
->next
= Type::tvoid
;
2881 tbret
= tret
->toBasetype();
2884 if (inferRef
) // deduce 'auto ref'
2887 if (tbret
->ty
!= Tvoid
) // if non-void return
2889 if (tbret
->ty
!= Terror
)
2890 rs
->error("return expression expected");
2893 else if (fd
->isMain())
2895 // main() returns 0, even if it returns void
2896 rs
->exp
= new IntegerExp(0);
2900 // If any branches have called a ctor, but this branch hasn't, it's an error
2901 if (sc
->callSuper
& CSXany_ctor
&&
2902 !(sc
->callSuper
& (CSXthis_ctor
| CSXsuper_ctor
)))
2904 rs
->error("return without calling constructor");
2907 sc
->callSuper
|= CSXreturn
;
2910 AggregateDeclaration
*ad
= fd
->isMember2();
2912 size_t dim
= sc
->fieldinit_dim
;
2913 for (size_t i
= 0; i
< dim
; i
++)
2915 VarDeclaration
*v
= ad
->fields
[i
];
2916 bool mustInit
= (v
->storage_class
& STCnodefaultctor
||
2917 v
->type
->needsNested());
2918 if (mustInit
&& !(sc
->fieldinit
[i
] & CSXthis_ctor
))
2920 rs
->error("an earlier return statement skips field %s initialization", v
->toChars());
2923 sc
->fieldinit
[i
] |= CSXreturn
;
2934 // Send out "case receiver" statement to the foreach.
2936 Statement
*s
= new ReturnStatement(Loc(), rs
->exp
);
2937 sc
->fes
->cases
->push(s
);
2939 // Immediately rewrite "this" return statement as:
2940 // return cases->length+1;
2941 rs
->exp
= new IntegerExp(sc
->fes
->cases
->length
+ 1);
2944 result
= new CompoundStatement(rs
->loc
, new ExpStatement(rs
->loc
, e0
), rs
);
2952 fd
->buildResultVar(NULL
, rs
->exp
->type
);
2953 bool r
= fd
->vresult
->checkNestedReference(sc
, Loc());
2954 assert(!r
); // vresult should be always accessible
2956 // Send out "case receiver" statement to the foreach.
2958 Statement
*s
= new ReturnStatement(Loc(), new VarExp(Loc(), fd
->vresult
));
2959 sc
->fes
->cases
->push(s
);
2961 // Save receiver index for the later rewriting from:
2964 // vresult = exp; retrun caseDim;
2965 rs
->caseDim
= sc
->fes
->cases
->length
+ 1;
2971 fd
->returns
= new ReturnStatements();
2972 fd
->returns
->push(rs
);
2976 result
= new CompoundStatement(rs
->loc
, new ExpStatement(rs
->loc
, e0
), rs
);
2982 void visit(BreakStatement
*bs
)
2984 //printf("BreakStatement::semantic()\n");
2986 // break Identifier;
2989 bs
->ident
= fixupLabelName(sc
, bs
->ident
);
2991 FuncDeclaration
*thisfunc
= sc
->func
;
2993 for (Scope
*scx
= sc
; scx
; scx
= scx
->enclosing
)
2995 if (scx
->func
!= thisfunc
) // if in enclosing function
2997 if (sc
->fes
) // if this is the body of a foreach
2999 /* Post this statement to the fes, and replace
3000 * it with a return value that caller will put into
3001 * a switch. Caller will figure out where the break
3002 * label actually is.
3003 * Case numbers start with 2, not 0, as 0 is continue
3006 sc
->fes
->cases
->push(bs
);
3007 result
= new ReturnStatement(Loc(), new IntegerExp(sc
->fes
->cases
->length
+ 1));
3010 break; // can't break to it
3013 LabelStatement
*ls
= scx
->slabel
;
3014 if (ls
&& ls
->ident
== bs
->ident
)
3016 Statement
*s
= ls
->statement
;
3018 if (!s
|| !s
->hasBreak())
3019 bs
->error("label `%s` has no break", bs
->ident
->toChars());
3020 else if (ls
->tf
!= sc
->tf
)
3021 bs
->error("cannot break out of finally block");
3031 bs
->error("enclosing label `%s` for break not found", bs
->ident
->toChars());
3034 else if (!sc
->sbreak
)
3036 if (sc
->os
&& sc
->os
->tok
!= TOKon_scope_failure
)
3038 bs
->error("break is not inside %s bodies", Token::toChars(sc
->os
->tok
));
3042 // Replace break; with return 1;
3043 result
= new ReturnStatement(Loc(), new IntegerExp(1));
3047 bs
->error("break is not inside a loop or switch");
3050 else if (sc
->sbreak
->isForwardingStatement())
3052 bs
->error("must use labeled `break` within `static foreach`");
3057 void visit(ContinueStatement
*cs
)
3059 //printf("ContinueStatement::semantic() %p\n", cs);
3062 cs
->ident
= fixupLabelName(sc
, cs
->ident
);
3065 FuncDeclaration
*thisfunc
= sc
->func
;
3067 for (scx
= sc
; scx
; scx
= scx
->enclosing
)
3071 if (scx
->func
!= thisfunc
) // if in enclosing function
3073 if (sc
->fes
) // if this is the body of a foreach
3075 for (; scx
; scx
= scx
->enclosing
)
3078 if (ls
&& ls
->ident
== cs
->ident
&& ls
->statement
== sc
->fes
)
3080 // Replace continue ident; with return 0;
3081 result
= new ReturnStatement(Loc(), new IntegerExp(0));
3086 /* Post this statement to the fes, and replace
3087 * it with a return value that caller will put into
3088 * a switch. Caller will figure out where the break
3089 * label actually is.
3090 * Case numbers start with 2, not 0, as 0 is continue
3093 sc
->fes
->cases
->push(cs
);
3094 result
= new ReturnStatement(Loc(), new IntegerExp(sc
->fes
->cases
->length
+ 1));
3097 break; // can't continue to it
3101 if (ls
&& ls
->ident
== cs
->ident
)
3103 Statement
*s
= ls
->statement
;
3105 if (!s
|| !s
->hasContinue())
3106 cs
->error("label `%s` has no continue", cs
->ident
->toChars());
3107 else if (ls
->tf
!= sc
->tf
)
3108 cs
->error("cannot continue out of finally block");
3117 cs
->error("enclosing label `%s` for continue not found", cs
->ident
->toChars());
3120 else if (!sc
->scontinue
)
3122 if (sc
->os
&& sc
->os
->tok
!= TOKon_scope_failure
)
3124 cs
->error("continue is not inside %s bodies", Token::toChars(sc
->os
->tok
));
3128 // Replace continue; with return 0;
3129 result
= new ReturnStatement(Loc(), new IntegerExp(0));
3133 cs
->error("continue is not inside a loop");
3136 else if (sc
->scontinue
->isForwardingStatement())
3138 cs
->error("must use labeled `continue` within `static foreach`");
3143 void visit(SynchronizedStatement
*ss
)
3147 ss
->exp
= expressionSemantic(ss
->exp
, sc
);
3148 ss
->exp
= resolveProperties(sc
, ss
->exp
);
3149 ss
->exp
= ss
->exp
->optimize(WANTvalue
);
3150 ss
->exp
= checkGC(sc
, ss
->exp
);
3151 if (ss
->exp
->op
== TOKerror
)
3153 ClassDeclaration
*cd
= ss
->exp
->type
->isClassHandle();
3156 ss
->error("can only synchronize on class objects, not `%s`", ss
->exp
->type
->toChars());
3159 else if (cd
->isInterfaceDeclaration())
3161 /* Cast the interface to an object, as the object has the monitor,
3162 * not the interface.
3164 if (!ClassDeclaration::object
)
3166 ss
->error("missing or corrupt object.d");
3170 Type
*t
= ClassDeclaration::object
->type
;
3171 t
= typeSemantic(t
, Loc(), sc
)->toBasetype();
3172 assert(t
->ty
== Tclass
);
3174 ss
->exp
= new CastExp(ss
->loc
, ss
->exp
, t
);
3175 ss
->exp
= expressionSemantic(ss
->exp
, sc
);
3180 * _d_monitorenter(tmp);
3181 * try { body } finally { _d_monitorexit(tmp); }
3183 VarDeclaration
*tmp
= copyToTemp(0, "__sync", ss
->exp
);
3184 dsymbolSemantic(tmp
, sc
);
3186 Statements
*cs
= new Statements();
3187 cs
->push(new ExpStatement(ss
->loc
, tmp
));
3189 Parameters
* args
= new Parameters
;
3190 args
->push(new Parameter(0, ClassDeclaration::object
->type
, NULL
, NULL
, NULL
));
3192 FuncDeclaration
*fdenter
= FuncDeclaration::genCfunc(args
, Type::tvoid
, Id::monitorenter
);
3193 Expression
*e
= new CallExp(ss
->loc
, new VarExp(ss
->loc
, fdenter
, false), new VarExp(ss
->loc
, tmp
));
3194 e
->type
= Type::tvoid
; // do not run semantic on e
3195 cs
->push(new ExpStatement(ss
->loc
, e
));
3197 FuncDeclaration
*fdexit
= FuncDeclaration::genCfunc(args
, Type::tvoid
, Id::monitorexit
);
3198 e
= new CallExp(ss
->loc
, new VarExp(ss
->loc
, fdexit
, false), new VarExp(ss
->loc
, tmp
));
3199 e
->type
= Type::tvoid
; // do not run semantic on e
3200 Statement
*s
= new ExpStatement(ss
->loc
, e
);
3201 s
= new TryFinallyStatement(ss
->loc
, ss
->_body
, s
);
3204 s
= new CompoundStatement(ss
->loc
, cs
);
3205 result
= statementSemantic(s
, sc
);
3210 /* Generate our own critical section, then rewrite as:
3211 * __gshared void* __critsec;
3212 * _d_criticalenter2(&__critsec);
3213 * try { body } finally { _d_criticalexit(__critsec); }
3215 Identifier
*id
= Identifier::generateId("__critsec");
3216 Type
*t
= Type::tvoidptr
;
3217 VarDeclaration
*tmp
= new VarDeclaration(ss
->loc
, t
, id
, NULL
);
3218 tmp
->storage_class
|= STCtemp
| STCgshared
| STCstatic
;
3219 Expression
*tmpExp
= new VarExp(ss
->loc
, tmp
);
3221 Statements
*cs
= new Statements();
3222 cs
->push(new ExpStatement(ss
->loc
, tmp
));
3224 /* This is just a dummy variable for "goto skips declaration" error.
3225 * Backend optimizer could remove this unused variable.
3227 VarDeclaration
*v
= new VarDeclaration(ss
->loc
, Type::tvoidptr
, Identifier::generateId("__sync"), NULL
);
3228 dsymbolSemantic(v
, sc
);
3229 cs
->push(new ExpStatement(ss
->loc
, v
));
3231 Parameters
* args
= new Parameters
;
3232 args
->push(new Parameter(0, t
->pointerTo(), NULL
, NULL
, NULL
));
3234 FuncDeclaration
*fdenter
= FuncDeclaration::genCfunc(args
, Type::tvoid
, Id::criticalenter
, STCnothrow
);
3235 Expression
*e
= new AddrExp(ss
->loc
, tmpExp
);
3236 e
= expressionSemantic(e
, sc
);
3237 e
= new CallExp(ss
->loc
, new VarExp(ss
->loc
, fdenter
, false), e
);
3238 e
->type
= Type::tvoid
; // do not run semantic on e
3239 cs
->push(new ExpStatement(ss
->loc
, e
));
3241 FuncDeclaration
*fdexit
= FuncDeclaration::genCfunc(args
, Type::tvoid
, Id::criticalexit
, STCnothrow
);
3242 e
= expressionSemantic(tmpExp
, sc
);
3243 e
= new CallExp(ss
->loc
, new VarExp(ss
->loc
, fdexit
, false), e
);
3244 e
->type
= Type::tvoid
; // do not run semantic on e
3245 Statement
*s
= new ExpStatement(ss
->loc
, e
);
3246 s
= new TryFinallyStatement(ss
->loc
, ss
->_body
, s
);
3249 s
= new CompoundStatement(ss
->loc
, cs
);
3250 result
= statementSemantic(s
, sc
);
3255 ss
->_body
= statementSemantic(ss
->_body
, sc
);
3256 if (ss
->_body
&& ss
->_body
->isErrorStatement())
3264 void visit(WithStatement
*ws
)
3269 //printf("WithStatement::semantic()\n");
3270 ws
->exp
= expressionSemantic(ws
->exp
, sc
);
3271 ws
->exp
= resolveProperties(sc
, ws
->exp
);
3272 ws
->exp
= ws
->exp
->optimize(WANTvalue
);
3273 ws
->exp
= checkGC(sc
, ws
->exp
);
3274 if (ws
->exp
->op
== TOKerror
)
3276 if (ws
->exp
->op
== TOKscope
)
3278 sym
= new WithScopeSymbol(ws
);
3279 sym
->parent
= sc
->scopesym
;
3280 sym
->endlinnum
= ws
->endloc
.linnum
;
3282 else if (ws
->exp
->op
== TOKtype
)
3284 Dsymbol
*s
= ((TypeExp
*)ws
->exp
)->type
->toDsymbol(sc
);
3285 if (!s
|| !s
->isScopeDsymbol())
3287 ws
->error("with type %s has no members", ws
->exp
->toChars());
3290 sym
= new WithScopeSymbol(ws
);
3291 sym
->parent
= sc
->scopesym
;
3292 sym
->endlinnum
= ws
->endloc
.linnum
;
3296 Type
*t
= ws
->exp
->type
->toBasetype();
3298 Expression
*olde
= ws
->exp
;
3299 if (t
->ty
== Tpointer
)
3301 ws
->exp
= new PtrExp(ws
->loc
, ws
->exp
);
3302 ws
->exp
= expressionSemantic(ws
->exp
, sc
);
3303 t
= ws
->exp
->type
->toBasetype();
3307 t
= t
->toBasetype();
3308 if (t
->isClassHandle())
3310 init
= new ExpInitializer(ws
->loc
, ws
->exp
);
3311 ws
->wthis
= new VarDeclaration(ws
->loc
, ws
->exp
->type
, Id::withSym
, init
);
3312 dsymbolSemantic(ws
->wthis
, sc
);
3314 sym
= new WithScopeSymbol(ws
);
3315 sym
->parent
= sc
->scopesym
;
3316 sym
->endlinnum
= ws
->endloc
.linnum
;
3318 else if (t
->ty
== Tstruct
)
3320 if (!ws
->exp
->isLvalue())
3324 * auto __withtmp = exp
3331 VarDeclaration
*tmp
= copyToTemp(0, "__withtmp", ws
->exp
);
3332 dsymbolSemantic(tmp
, sc
);
3333 ExpStatement
*es
= new ExpStatement(ws
->loc
, tmp
);
3334 ws
->exp
= new VarExp(ws
->loc
, tmp
);
3335 Statement
*ss
= new ScopeStatement(ws
->loc
, new CompoundStatement(ws
->loc
, es
, ws
), ws
->endloc
);
3336 result
= statementSemantic(ss
, sc
);
3339 Expression
*e
= ws
->exp
->addressOf();
3340 init
= new ExpInitializer(ws
->loc
, e
);
3341 ws
->wthis
= new VarDeclaration(ws
->loc
, e
->type
, Id::withSym
, init
);
3342 dsymbolSemantic(ws
->wthis
, sc
);
3343 sym
= new WithScopeSymbol(ws
);
3344 // Need to set the scope to make use of resolveAliasThis
3346 sym
->parent
= sc
->scopesym
;
3347 sym
->endlinnum
= ws
->endloc
.linnum
;
3351 ws
->error("with expressions must be aggregate types or pointers to them, not `%s`", olde
->type
->toChars());
3361 ws
->_body
= statementSemantic(ws
->_body
, sc
);
3363 if (ws
->_body
&& ws
->_body
->isErrorStatement())
3373 void visit(TryCatchStatement
*tcs
)
3375 if (!global
.params
.useExceptions
)
3377 tcs
->error("Cannot use try-catch statements with -betterC");
3381 if (!ClassDeclaration::throwable
)
3383 tcs
->error("Cannot use try-catch statements because `object.Throwable` was not declared");
3388 const unsigned FLAGcpp
= 1;
3389 const unsigned FLAGd
= 2;
3391 tcs
->_body
= semanticScope(tcs
->_body
, sc
, NULL
, NULL
);
3394 /* Even if body is empty, still do semantic analysis on catches
3396 bool catchErrors
= false;
3397 for (size_t i
= 0; i
< tcs
->catches
->length
; i
++)
3399 Catch
*c
= (*tcs
->catches
)[i
];
3400 catchSemantic(c
, sc
);
3406 ClassDeclaration
*cd
= c
->type
->toBasetype()->isClassHandle();
3407 flags
|= cd
->isCPPclass() ? FLAGcpp
: FLAGd
;
3409 // Determine if current catch 'hides' any previous catches
3410 for (size_t j
= 0; j
< i
; j
++)
3412 Catch
*cj
= (*tcs
->catches
)[j
];
3413 const char *si
= c
->loc
.toChars();
3414 const char *sj
= cj
->loc
.toChars();
3416 if (c
->type
->toBasetype()->implicitConvTo(cj
->type
->toBasetype()))
3418 tcs
->error("catch at %s hides catch at %s", sj
, si
);
3426 if (flags
== (FLAGcpp
| FLAGd
))
3428 tcs
->error("cannot mix catching D and C++ exceptions in the same try-catch");
3436 if (tcs
->_body
->isErrorStatement())
3438 result
= tcs
->_body
;
3442 /* If the try body never throws, we can eliminate any catches
3443 * of recoverable exceptions.
3446 if (!(blockExit(tcs
->_body
, sc
->func
, false) & BEthrow
) && ClassDeclaration::exception
)
3448 for (size_t i
= 0; i
< tcs
->catches
->length
; i
++)
3450 Catch
*c
= (*tcs
->catches
)[i
];
3452 /* If catch exception type is derived from Exception
3454 if (c
->type
->toBasetype()->implicitConvTo(ClassDeclaration::exception
->type
) &&
3455 (!c
->handler
|| !c
->handler
->comeFrom()))
3457 // Remove c from the array of catches
3458 tcs
->catches
->remove(i
);
3464 if (tcs
->catches
->length
== 0)
3466 result
= tcs
->_body
->hasCode() ? tcs
->_body
: NULL
;
3473 void visit(TryFinallyStatement
*tfs
)
3475 //printf("TryFinallyStatement::semantic()\n");
3476 tfs
->_body
= statementSemantic(tfs
->_body
, sc
);
3480 sc
->scontinue
= NULL
; // no break or continue out of finally block
3481 tfs
->finalbody
= semanticNoScope(tfs
->finalbody
, sc
);
3486 result
= tfs
->finalbody
;
3490 if (!tfs
->finalbody
)
3492 result
= tfs
->_body
;
3496 int blockexit
= blockExit(tfs
->_body
, sc
->func
, false);
3498 // if not worrying about exceptions
3499 if (!(global
.params
.useExceptions
&& ClassDeclaration::throwable
))
3500 blockexit
&= ~BEthrow
; // don't worry about paths that otherwise may throw
3502 // Don't care about paths that halt, either
3503 if ((blockexit
& ~BEhalt
) == BEfallthru
)
3505 result
= new CompoundStatement(tfs
->loc
, tfs
->_body
, tfs
->finalbody
);
3511 void visit(ScopeGuardStatement
*oss
)
3513 if (oss
->tok
!= TOKon_scope_exit
)
3515 // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
3516 // so the generated catch block cannot be placed in finally block.
3517 // See also Catch::semantic.
3518 if (sc
->os
&& sc
->os
->tok
!= TOKon_scope_failure
)
3520 // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
3521 oss
->error("cannot put %s statement inside %s", Token::toChars(oss
->tok
), Token::toChars(sc
->os
->tok
));
3526 oss
->error("cannot put %s statement inside finally block", Token::toChars(oss
->tok
));
3534 if (oss
->tok
!= TOKon_scope_failure
)
3536 // Jump out from scope(failure) block is allowed.
3538 sc
->scontinue
= NULL
;
3540 oss
->statement
= semanticNoScope(oss
->statement
, sc
);
3543 if (!oss
->statement
|| oss
->statement
->isErrorStatement())
3545 result
= oss
->statement
;
3551 void visit(ThrowStatement
*ts
)
3553 //printf("ThrowStatement::semantic()\n");
3555 if (!global
.params
.useExceptions
)
3557 ts
->error("Cannot use `throw` statements with -betterC");
3561 if (!ClassDeclaration::throwable
)
3563 ts
->error("Cannot use `throw` statements because `object.Throwable` was not declared");
3567 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
3568 fd
->hasReturnExp
|= 2;
3570 ts
->exp
= expressionSemantic(ts
->exp
, sc
);
3571 ts
->exp
= resolveProperties(sc
, ts
->exp
);
3572 ts
->exp
= checkGC(sc
, ts
->exp
);
3573 if (ts
->exp
->op
== TOKerror
)
3576 checkThrowEscape(sc
, ts
->exp
, false);
3578 ClassDeclaration
*cd
= ts
->exp
->type
->toBasetype()->isClassHandle();
3579 if (!cd
|| ((cd
!= ClassDeclaration::throwable
) && !ClassDeclaration::throwable
->isBaseOf(cd
, NULL
)))
3581 ts
->error("can only throw class objects derived from Throwable, not type %s", ts
->exp
->type
->toChars());
3588 void visit(DebugStatement
*ds
)
3593 sc
->flags
|= SCOPEdebug
;
3594 ds
->statement
= statementSemantic(ds
->statement
, sc
);
3597 result
= ds
->statement
;
3600 void visit(GotoStatement
*gs
)
3602 //printf("GotoStatement::semantic()\n");
3603 FuncDeclaration
*fd
= sc
->func
;
3605 gs
->ident
= fixupLabelName(sc
, gs
->ident
);
3606 gs
->label
= fd
->searchLabel(gs
->ident
);
3609 gs
->lastVar
= sc
->lastVar
;
3611 if (!gs
->label
->statement
&& sc
->fes
)
3613 /* Either the goto label is forward referenced or it
3614 * is in the function that the enclosing foreach is in.
3615 * Can't know yet, so wrap the goto in a scope statement
3616 * so we can patch it later, and add it to a 'look at this later'
3619 ScopeStatement
*ss
= new ScopeStatement(gs
->loc
, gs
, gs
->loc
);
3620 sc
->fes
->gotos
->push(ss
); // 'look at this later' list
3625 // Add to fwdref list to check later
3626 if (!gs
->label
->statement
)
3629 fd
->gotos
= new GotoStatements();
3630 fd
->gotos
->push(gs
);
3632 else if (gs
->checkLabel())
3638 void visit(LabelStatement
*ls
)
3640 //printf("LabelStatement::semantic()\n");
3641 FuncDeclaration
*fd
= sc
->parent
->isFuncDeclaration();
3643 ls
->ident
= fixupLabelName(sc
, ls
->ident
);
3646 ls
->lastVar
= sc
->lastVar
;
3648 LabelDsymbol
*ls2
= fd
->searchLabel(ls
->ident
);
3651 ls
->error("label `%s` already defined", ls2
->toChars());
3655 ls2
->statement
= ls
;
3658 sc
->scopesym
= sc
->enclosing
->scopesym
;
3659 sc
->callSuper
|= CSXlabel
;
3662 size_t dim
= sc
->fieldinit_dim
;
3663 for (size_t i
= 0; i
< dim
; i
++)
3664 sc
->fieldinit
[i
] |= CSXlabel
;
3668 ls
->statement
= statementSemantic(ls
->statement
, sc
);
3674 void visit(AsmStatement
*s
)
3676 result
= asmSemantic(s
, sc
);
3679 void visit(CompoundAsmStatement
*cas
)
3681 // Apply postfix attributes of the asm block to each statement.
3683 sc
->stc
|= cas
->stc
;
3685 for (size_t i
= 0; i
< cas
->statements
->length
; i
++)
3687 Statement
*s
= (*cas
->statements
)[i
];
3688 (*cas
->statements
)[i
] = s
? statementSemantic(s
, sc
) : NULL
;
3692 // use setImpure/setGC when the deprecation cycle is over
3694 if (!(cas
->stc
& STCpure
) && (purity
= sc
->func
->isPureBypassingInference()) != PUREimpure
&& purity
!= PUREfwdref
)
3695 cas
->deprecation("asm statement is assumed to be impure - mark it with `pure` if it is not");
3696 if (!(cas
->stc
& STCnogc
) && sc
->func
->isNogcBypassingInference())
3697 cas
->deprecation("asm statement is assumed to use the GC - mark it with `@nogc` if it does not");
3698 if (!(cas
->stc
& (STCtrusted
|STCsafe
)) && sc
->func
->setUnsafe())
3699 cas
->error("asm statement is assumed to be @system - mark it with `@trusted` if it is not");
3705 void visit(ImportStatement
*imps
)
3707 for (size_t i
= 0; i
< imps
->imports
->length
; i
++)
3709 Import
*s
= (*imps
->imports
)[i
]->isImport();
3710 assert(!s
->aliasdecls
.length
);
3711 for (size_t j
= 0; j
< s
->names
.length
; j
++)
3713 Identifier
*name
= s
->names
[j
];
3714 Identifier
*alias
= s
->aliases
[j
];
3719 TypeIdentifier
*tname
= new TypeIdentifier(s
->loc
, name
);
3720 AliasDeclaration
*ad
= new AliasDeclaration(s
->loc
, alias
, tname
);
3722 s
->aliasdecls
.push(ad
);
3725 dsymbolSemantic(s
, sc
);
3726 // https://issues.dlang.org/show_bug.cgi?id=19942
3727 // If the module that's being imported doesn't exist, don't add it to the symbol table
3728 // for the current scope.
3731 Module::addDeferredSemantic2(s
); // Bugzilla 14666
3734 for (size_t j
= 0; j
< s
->aliasdecls
.length
; j
++)
3736 sc
->insert(s
->aliasdecls
[j
]);
3744 Statement
*statementSemantic(Statement
*s
, Scope
*sc
)
3746 StatementSemanticVisitor v
= StatementSemanticVisitor(sc
);
3751 void catchSemantic(Catch
*c
, Scope
*sc
)
3753 //printf("Catch::semantic(%s)\n", ident->toChars());
3755 if (sc
->os
&& sc
->os
->tok
!= TOKon_scope_failure
)
3757 // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
3758 error(c
->loc
, "cannot put catch statement inside %s", Token::toChars(sc
->os
->tok
));
3763 /* This is because the _d_local_unwind() gets the stack munged
3764 * up on this. The workaround is to place any try-catches into
3765 * a separate function, and call that.
3766 * To fix, have the compiler automatically convert the finally
3767 * body into a nested function.
3769 error(c
->loc
, "cannot put catch statement inside finally block");
3773 ScopeDsymbol
*sym
= new ScopeDsymbol();
3774 sym
->parent
= sc
->scopesym
;
3779 deprecation(c
->loc
, "catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior");
3781 // reference .object.Throwable
3782 c
->type
= getThrowable();
3784 c
->type
= typeSemantic(c
->type
, c
->loc
, sc
);
3785 if (c
->type
== Type::terror
)
3789 ClassDeclaration
*cd
= c
->type
->toBasetype()->isClassHandle();
3792 error(c
->loc
, "can only catch class objects, not `%s`", c
->type
->toChars());
3795 else if (cd
->isCPPclass())
3797 if (!target
.cpp
.exceptions
)
3799 error(c
->loc
, "catching C++ class objects not supported for this target");
3802 if (sc
->func
&& !sc
->intypeof
&& !c
->internalCatch
&& sc
->func
->setUnsafe())
3804 error(c
->loc
, "cannot catch C++ class objects in @safe code");
3808 else if (cd
!= ClassDeclaration::throwable
&& !ClassDeclaration::throwable
->isBaseOf(cd
, NULL
))
3810 error(c
->loc
, "can only catch class objects derived from Throwable, not `%s`", c
->type
->toChars());
3813 else if (sc
->func
&& !sc
->intypeof
&& !c
->internalCatch
&&
3814 cd
!= ClassDeclaration::exception
&& !ClassDeclaration::exception
->isBaseOf(cd
, NULL
) &&
3815 sc
->func
->setUnsafe())
3817 error(c
->loc
, "can only catch class objects derived from Exception in @safe code, not `%s`", c
->type
->toChars());
3823 c
->var
= new VarDeclaration(c
->loc
, c
->type
, c
->ident
, NULL
);
3824 dsymbolSemantic(c
->var
, sc
);
3827 c
->handler
= statementSemantic(c
->handler
, sc
);
3828 if (c
->handler
&& c
->handler
->isErrorStatement())
3834 Statement
*semanticNoScope(Statement
*s
, Scope
*sc
)
3836 //printf("Statement::semanticNoScope() %s\n", toChars());
3837 if (!s
->isCompoundStatement() && !s
->isScopeStatement())
3839 s
= new CompoundStatement(s
->loc
, s
); // so scopeCode() gets called
3841 s
= statementSemantic(s
, sc
);
3845 // Same as semanticNoScope(), but do create a new scope
3846 Statement
*semanticScope(Statement
*s
, Scope
*sc
, Statement
*sbreak
, Statement
*scontinue
)
3848 ScopeDsymbol
*sym
= new ScopeDsymbol();
3849 sym
->parent
= sc
->scopesym
;
3850 Scope
*scd
= sc
->push(sym
);
3852 scd
->sbreak
= sbreak
;
3854 scd
->scontinue
= scontinue
;
3855 s
= semanticNoScope(s
, scd
);
3860 /*******************
3861 * See StatementSemanticVisitor.makeTupleForeach. This is a simple
3862 * wrapper that returns the generated statements/declarations.
3864 Statement
*makeTupleForeachStatic(Scope
*sc
, ForeachStatement
*fs
, bool needExpansion
)
3866 StatementSemanticVisitor v
= StatementSemanticVisitor(sc
);
3867 v
.makeTupleForeachStatic(fs
, needExpansion
);
3871 Dsymbols
*makeTupleForeachStaticDecl(Scope
*sc
, ForeachStatement
*fs
, Dsymbols
*dbody
, bool needExpansion
)
3873 StatementSemanticVisitor v
= StatementSemanticVisitor(sc
);
3874 return v
.makeTupleForeachStaticDecl(fs
, dbody
, needExpansion
);