void EnumMember::semantic(Scope *sc) { //printf("EnumMember::semantic() %s\n", toChars()); if (errors || semanticRun >= PASSsemanticdone) return; if (semanticRun == PASSsemantic) { error("circular reference to enum member"); Lerrors: errors = true; semanticRun = PASSsemanticdone; return; } assert(ed); ed->semantic(sc); if (ed->errors) goto Lerrors; if (errors || semanticRun >= PASSsemanticdone) return; semanticRun = PASSsemantic; if (scope) sc = scope; // The first enum member is special bool first = (this == (*ed->members)[0]); if (type) { type = type->semantic(loc, sc); assert(value); // "type id;" is not a valid enum member declaration } if (value) { Expression *e = value; assert(e->dyncast() == DYNCAST_EXPRESSION); e = e->semantic(sc); e = resolveProperties(sc, e); e = e->ctfeInterpret(); if (e->op == TOKerror) goto Lerrors; if (first && !ed->memtype && !ed->isAnonymous()) { ed->memtype = e->type; if (ed->memtype->ty == Terror) { ed->errors = true; goto Lerrors; } if (ed->memtype->ty != Terror) { /* Bugzilla 11746: All of named enum members should have same type * with the first member. If the following members were referenced * during the first member semantic, their types should be unified. */ for (size_t i = 0; i < ed->members->dim; i++) { EnumMember *em = (*ed->members)[i]->isEnumMember(); if (!em || em == this || em->semanticRun < PASSsemanticdone || em->type) continue; //printf("[%d] em = %s, em->semanticRun = %d\n", i, toChars(), em->semanticRun); Expression *ev = em->value; ev = ev->implicitCastTo(sc, ed->memtype); ev = ev->ctfeInterpret(); ev = ev->castTo(sc, ed->type); if (ev->op == TOKerror) ed->errors = true; em->value = ev; } if (ed->errors) { ed->memtype = Type::terror; goto Lerrors; } } } if (ed->memtype && !type) { e = e->implicitCastTo(sc, ed->memtype); e = e->ctfeInterpret(); // save origValue for better json output origValue = e; if (!ed->isAnonymous()) e = e->castTo(sc, ed->type); } else if (type) { e = e->implicitCastTo(sc, type); e = e->ctfeInterpret(); assert(ed->isAnonymous()); // save origValue for better json output origValue = e; } value = e; } else if (first) { Type *t; if (ed->memtype) t = ed->memtype; else { t = Type::tint32; if (!ed->isAnonymous()) ed->memtype = t; } Expression *e = new IntegerExp(loc, 0, Type::tint32); e = e->implicitCastTo(sc, t); e = e->ctfeInterpret(); // save origValue for better json output origValue = e; if (!ed->isAnonymous()) e = e->castTo(sc, ed->type); value = e; } else { /* Find the previous enum member, * and set this to be the previous value + 1 */ EnumMember *emprev = NULL; for (size_t i = 0; i < ed->members->dim; i++) { EnumMember *em = (*ed->members)[i]->isEnumMember(); if (em) { if (em == this) break; emprev = em; } } assert(emprev); if (emprev->semanticRun < PASSsemanticdone) // if forward reference emprev->semantic(emprev->scope); // resolve it if (emprev->errors) goto Lerrors; Expression *eprev = emprev->value; Type *tprev = eprev->type->equals(ed->type) ? ed->memtype : eprev->type; Expression *emax = tprev->getProperty(ed->loc, Id::max, 0); emax = emax->semantic(sc); emax = emax->ctfeInterpret(); // Set value to (eprev + 1). // But first check that (eprev != emax) assert(eprev); Expression *e = new EqualExp(TOKequal, loc, eprev, emax); e = e->semantic(sc); e = e->ctfeInterpret(); if (e->toInteger()) { error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev->ed->toChars(), emprev->toChars(), ed->type->toBasetype()->toChars()); goto Lerrors; } // Now set e to (eprev + 1) e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type::tint32)); e = e->semantic(sc); e = e->castTo(sc, eprev->type); e = e->ctfeInterpret(); // save origValue (without cast) for better json output if (e->op != TOKerror) // avoid duplicate diagnostics { assert(emprev->origValue); origValue = new AddExp(loc, emprev->origValue, new IntegerExp(loc, 1, Type::tint32)); origValue = origValue->semantic(sc); origValue = origValue->ctfeInterpret(); } if (e->op == TOKerror) goto Lerrors; if (e->type->isfloating()) { // Check that e != eprev (not always true for floats) Expression *etest = new EqualExp(TOKequal, loc, e, eprev); etest = etest->semantic(sc); etest = etest->ctfeInterpret(); if (etest->toInteger()) { error("has inexact value, due to loss of precision"); goto Lerrors; } } value = e; } assert(origValue); semanticRun = PASSsemanticdone; }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); if (needInterpret) sc = sc->startCTFE(); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (needInterpret) sc = sc->endCTFE(); if (exp->op == TOKerror) return new ErrorInitializer(); int olderrors = global.errors; if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages if (exp->op == TOKtype) { exp->error("initializer must be an expression, not '%s'", exp->toChars()); return new ErrorInitializer(); } // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(exp)) { exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars()); return new ErrorInitializer(); } Type *tb = t->toBasetype(); Type *ti = exp->type->toBasetype(); if (exp->op == TOKtuple && expandTuples && !exp->implicitConvTo(t)) return new ExpInitializer(loc, exp); /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; * Allow this by doing an explicit cast, which will lengthen the string * literal. */ if (exp->op == TOKstring && tb->ty == Tsarray && ti->ty == Tsarray) { StringExp *se = (StringExp *)exp; if (!se->committed && se->type->ty == Tsarray && ((TypeSArray *)se->type)->dim->toInteger() < ((TypeSArray *)t)->dim->toInteger()) { exp = se->castTo(sc, t); goto L1; } } // Look for implicit constructor call if (tb->ty == Tstruct && !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) && !exp->implicitConvTo(t)) { StructDeclaration *sd = ((TypeStruct *)tb)->sym; if (sd->ctor) { // Rewrite as S().ctor(exp) Expression *e; e = new StructLiteralExp(loc, sd, NULL); e = new DotIdExp(loc, e, Id::ctor); e = new CallExp(loc, e, exp); e = e->semantic(sc); if (needInterpret) exp = e->ctfeInterpret(); else exp = e->optimize(WANTvalue); } } // Look for the case of statically initializing an array // with a single member. if (tb->ty == Tsarray && !tb->nextOf()->equals(ti->toBasetype()->nextOf()) && exp->implicitConvTo(tb->nextOf()) ) { /* If the variable is not actually used in compile time, array creation is * redundant. So delay it until invocation of toExpression() or toDt(). */ t = tb->nextOf(); } exp = exp->implicitCastTo(sc, t); if (exp->op == TOKerror) return this; L1: if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
/********************************* * Operator overloading for op= */ Expression *BinAssignExp::op_overload(Scope *sc) { //printf("BinAssignExp::op_overload() (%s)\n", toChars()); #if DMDV2 if (e1->op == TOKarray) { ArrayExp *ae = (ArrayExp *)e1; ae->e1 = ae->e1->semantic(sc); ae->e1 = resolveProperties(sc, ae->e1); AggregateDeclaration *ad = isAggregate(ae->e1->type); if (ad) { /* Rewrite a[args]+=e2 as: * a.opIndexOpAssign!("+")(e2, args); */ Dsymbol *fd = search_function(ad, Id::opIndexOpAssign); if (fd) { Expression *e0 = resolveOpDollar(sc, ae); Expressions *a = (Expressions *)ae->arguments->copy(); a->insert(0, e2); Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, tiargs); e = new CallExp(loc, e, a); e = combine(e0, e); e = e->semantic(sc); return e; } // Didn't find it. Forward to aliasthis if (ad->aliasthis && ae->e1->type != att1) { /* Rewrite a[arguments] op= e2 as: * a.aliasthis[arguments] op= e2 */ Expression *e1 = ae->copy(); ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); BinExp *be = (BinExp *)copy(); if (!be->att1 && ae->e1->type->checkAliasThisRec()) be->att1 = ae->e1->type; be->e1 = e1; if (Expression *e = be->trySemantic(sc)) return e; } att1 = NULL; } } else if (e1->op == TOKslice) { SliceExp *se = (SliceExp *)e1; se->e1 = se->e1->semantic(sc); se->e1 = resolveProperties(sc, se->e1); AggregateDeclaration *ad = isAggregate(se->e1->type); if (ad) { /* Rewrite a[lwr..upr]+=e2 as: * a.opSliceOpAssign!("+")(e2, lwr, upr); */ Dsymbol *fd = search_function(ad, Id::opSliceOpAssign); if (fd) { Expression *e0 = resolveOpDollar(sc, se); Expressions *a = new Expressions(); a->push(e2); assert(!se->lwr || se->upr); if (se->lwr) { a->push(se->lwr); a->push(se->upr); } Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, tiargs); e = new CallExp(loc, e, a); e = combine(e0, e); e = e->semantic(sc); return e; } // Didn't find it. Forward to aliasthis if (ad->aliasthis && se->e1->type != att1) { /* Rewrite a[lwr..upr] op= e2 as: * a.aliasthis[lwr..upr] op= e2 */ Expression *e1 = se->copy(); ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident); BinExp *be = (BinExp *)copy(); if (!be->att1 && se->e1->type->checkAliasThisRec()) be->att1 = se->e1->type; be->e1 = e1; if (Expression *e = be->trySemantic(sc)) return e; } att1 = NULL; } } #endif BinExp::semantic(sc); e1 = resolveProperties(sc, e1); e2 = resolveProperties(sc, e2); // Don't attempt 'alias this' if an error occured if (e1->type->ty == Terror || e2->type->ty == Terror) return new ErrorExp(); Identifier *id = opId(); Expressions args2; AggregateDeclaration *ad1 = isAggregate(e1->type); Dsymbol *s = NULL; #if 1 // the old D1 scheme if (ad1 && id) { s = search_function(ad1, id); } #endif Objects *tiargs = NULL; #if DMDV2 if (!s) { /* Try the new D2 scheme, opOpAssign */ if (ad1) { s = search_function(ad1, Id::opOpAssign); if (s && !s->isTemplateDeclaration()) { error("%s.opOpAssign isn't a template", e1->toChars()); return new ErrorExp(); } } // Set tiargs, the template argument list, which will be the operator string if (s) { id = Id::opOpAssign; tiargs = opToArg(sc, op); } } #endif if (s) { /* Try: * a.opOpAssign(b) */ args2.setDim(1); args2[0] = e2; Match m; memset(&m, 0, sizeof(m)); m.last = MATCHnomatch; if (s) overloadResolveX(&m, s, loc, sc, tiargs, e1, &args2); if (m.count > 1) { // Error, ambiguous error("overloads %s and %s both match argument list for %s", m.lastf->type->toChars(), m.nextf->type->toChars(), m.lastf->toChars()); } else if (m.last == MATCHnomatch) { m.lastf = m.anyf; if (tiargs) goto L1; } // Rewrite (e1 op e2) as e1.opOpAssign(e2) return build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s); } L1: #if DMDV2 // Try alias this on first operand if (ad1 && ad1->aliasthis) { /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ if (att1 && this->e1->type == att1) return NULL; //printf("att %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars()); Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); BinExp *be = (BinExp *)copy(); if (!be->att1 && this->e1->type->checkAliasThisRec()) be->att1 = this->e1->type; be->e1 = e1; return be->trySemantic(sc); } // Try alias this on second operand AggregateDeclaration *ad2 = isAggregate(e2->type); if (ad2 && ad2->aliasthis) { /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ if (att2 && this->e2->type == att2) return NULL; //printf("att %s e2 = %s\n", Token::toChars(op), this->e2->type->toChars()); Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); BinExp *be = (BinExp *)copy(); if (!be->att2 && this->e2->type->checkAliasThisRec()) be->att2 = this->e2->type; be->e2 = e2; return be->trySemantic(sc); } #endif return NULL; }
void PragmaDeclaration::semantic(Scope *sc) { // Should be merged with PragmaStatement //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); if (ident == Id::msg) { if (args) { for (size_t i = 0; i < args->dim; i++) { Expression *e = (*args)[i]; sc = sc->startCTFE(); e = e->semantic(sc); e = resolveProperties(sc, e); sc = sc->endCTFE(); // pragma(msg) is allowed to contain types as well as expressions e = ctfeInterpretForPragmaMsg(e); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); return; } StringExp *se = e->toString(); if (se) { fprintf(stderr, "%.*s", (int)se->len, (char *)se->string); } else fprintf(stderr, "%s", e->toChars()); } fprintf(stderr, "\n"); } goto Lnodecl; } else if (ident == Id::lib) { if (!args || args->dim != 1) error("string expected for library name"); else { Expression *e = (*args)[0]; sc = sc->startCTFE(); e = e->semantic(sc); e = resolveProperties(sc, e); sc = sc->endCTFE(); e = e->ctfeInterpret(); (*args)[0] = e; if (e->op == TOKerror) goto Lnodecl; StringExp *se = e->toString(); if (!se) error("string expected for library name, not '%s'", e->toChars()); else { char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; if (global.params.verbose) fprintf(global.stdmsg, "library %s\n", name); if (global.params.moduleDeps && !global.params.moduleDepsFile) { OutBuffer *ob = global.params.moduleDeps; Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module; ob->writestring("depsLib "); ob->writestring(imod->toPrettyChars()); ob->writestring(" ("); escapePath(ob, imod->srcfile->toChars()); ob->writestring(") : "); ob->writestring((char *) name); ob->writenl(); } mem.free(name); } } goto Lnodecl; } else if (ident == Id::startaddress) { if (!args || args->dim != 1) error("function name expected for start address"); else { Expression *e = (*args)[0]; sc = sc->startCTFE(); e = e->semantic(sc); e = resolveProperties(sc, e); sc = sc->endCTFE(); e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) error("function name expected for start address, not '%s'", e->toChars()); } goto Lnodecl; } else if (ident == Id::mangle) { if (!args || args->dim != 1) error("string expected for mangled name"); else { Expression *e = (*args)[0]; e = e->semantic(sc); e = e->ctfeInterpret(); (*args)[0] = e; if (e->op == TOKerror) goto Lnodecl; StringExp *se = e->toString(); if (!se) { error("string expected for mangled name, not '%s'", e->toChars()); return; } if (!se->len) error("zero-length string not allowed for mangled name"); if (se->sz != 1) error("mangled name characters can only be of type char"); #if 1 /* Note: D language specification should not have any assumption about backend * implementation. Ideally pragma(mangle) can accept a string of any content. * * Therefore, this validation is compiler implementation specific. */ for (size_t i = 0; i < se->len; ) { utf8_t *p = (utf8_t *)se->string; dchar_t c = p[i]; if (c < 0x80) { if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c != 0 && strchr("$%().:?@[]_", c)) { ++i; continue; } else { error("char 0x%02x not allowed in mangled name", c); break; } } if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c)) { error("%s", msg); break; } if (!isUniAlpha(c)) { error("char 0x%04x not allowed in mangled name", c); break; } } #endif } } else if (global.params.ignoreUnsupportedPragmas) { if (global.params.verbose) { /* Print unrecognized pragmas */ fprintf(global.stdmsg, "pragma %s", ident->toChars()); if (args) { for (size_t i = 0; i < args->dim; i++) { Expression *e = (*args)[i]; sc = sc->startCTFE(); e = e->semantic(sc); e = resolveProperties(sc, e); sc = sc->endCTFE(); e = e->ctfeInterpret(); if (i == 0) fprintf(global.stdmsg, " ("); else fprintf(global.stdmsg, ","); fprintf(global.stdmsg, "%s", e->toChars()); } if (args->dim) fprintf(global.stdmsg, ")"); } fprintf(global.stdmsg, "\n"); } goto Lnodecl; } else error("unrecognized pragma(%s)", ident->toChars()); Ldecl: if (decl) { for (size_t i = 0; i < decl->dim; i++) { Dsymbol *s = (*decl)[i]; s->semantic(sc); if (ident == Id::mangle) { StringExp *e = (*args)[0]->toString(); char *name = (char *)mem.malloc(e->len + 1); memcpy(name, e->string, e->len); name[e->len] = 0; unsigned cnt = setMangleOverride(s, name); if (cnt > 1) error("can only apply to a single declaration"); } } } return; Lnodecl: if (decl) { error("pragma is missing closing ';'"); goto Ldecl; // do them anyway, to avoid segfaults. } }
int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply) { Identifier *idapply = (op == TOKforeach) ? Id::apply : Id::applyReverse; #if DMDV2 Identifier *idfront = (op == TOKforeach) ? Id::Ffront : Id::Fback; int sliced = 0; #endif Type *tab; Type *att = NULL; Expression *org_aggr = aggr; AggregateDeclaration *ad; while (1) { aggr = aggr->semantic(sc); aggr = resolveProperties(sc, aggr); aggr = aggr->optimize(WANTvalue); if (!aggr->type) goto Lerr; tab = aggr->type->toBasetype(); if (att == tab) { aggr = org_aggr; goto Lerr; } switch (tab->ty) { case Tarray: case Tsarray: case Ttuple: case Taarray: break; case Tclass: ad = ((TypeClass *)tab)->sym; goto Laggr; case Tstruct: ad = ((TypeStruct *)tab)->sym; goto Laggr; Laggr: #if DMDV2 if (!sliced) { sapply = search_function(ad, idapply); if (sapply) { // opApply aggregate break; } Dsymbol *s = search_function(ad, Id::slice); if (s) { Expression *rinit = new SliceExp(aggr->loc, aggr, NULL, NULL); rinit = rinit->trySemantic(sc); if (rinit) // if application of [] succeeded { aggr = rinit; sliced = 1; continue; } } } if (Dsymbol *shead = ad->search(Loc(), idfront, 0)) { // range aggregate break; } if (ad->aliasthis) { if (!att && tab->checkAliasThisRec()) att = tab; aggr = new DotIdExp(aggr->loc, aggr, ad->aliasthis->ident); continue; } #else sapply = search_function(ad, idapply); if (sapply) { // opApply aggregate break; } #endif goto Lerr; case Tdelegate: if (aggr->op == TOKdelegate) { DelegateExp *de = (DelegateExp *)aggr; sapply = de->func->isFuncDeclaration(); } break; case Terror: break; default: goto Lerr; } break; } return 1; Lerr: return 0; }
Expression *UnaExp::op_overload(Scope *sc) { //printf("UnaExp::op_overload() (%s)\n", toChars()); #if DMDV2 if (e1->op == TOKarray) { ArrayExp *ae = (ArrayExp *)e1; ae->e1 = ae->e1->semantic(sc); ae->e1 = resolveProperties(sc, ae->e1); AggregateDeclaration *ad = isAggregate(ae->e1->type); if (ad) { /* Rewrite as: * a.opIndexUnary!("+")(args); */ Dsymbol *fd = search_function(ad, Id::opIndexUnary); if (fd) { Expression *e0 = resolveOpDollar(sc, ae); Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, tiargs); e = new CallExp(loc, e, ae->arguments); e = combine(e0, e); e = e->semantic(sc); return e; } // Didn't find it. Forward to aliasthis if (ad->aliasthis && ae->e1->type != att1) { /* Rewrite op(a[arguments]) as: * op(a.aliasthis[arguments]) */ Expression *e1 = ae->copy(); ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); UnaExp *ue = (UnaExp *)copy(); if (!ue->att1 && ae->e1->type->checkAliasThisRec()) ue->att1 = ae->e1->type; ue->e1 = e1; if (Expression *e = ue->trySemantic(sc)) return e; } att1 = NULL; } } else if (e1->op == TOKslice) { SliceExp *se = (SliceExp *)e1; se->e1 = se->e1->semantic(sc); se->e1 = resolveProperties(sc, se->e1); AggregateDeclaration *ad = isAggregate(se->e1->type); if (ad) { /* Rewrite as: * a.opSliceUnary!("+")(lwr, upr); */ Dsymbol *fd = search_function(ad, Id::opSliceUnary); if (fd) { Expression *e0 = resolveOpDollar(sc, se); Expressions *a = new Expressions(); assert(!se->lwr || se->upr); if (se->lwr) { a->push(se->lwr); a->push(se->upr); } Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, tiargs); e = new CallExp(loc, e, a); e = combine(e0, e); e = e->semantic(sc); return e; } // Didn't find it. Forward to aliasthis if (ad->aliasthis && se->e1->type != att1) { /* Rewrite op(a[lwr..upr]) as: * op(a.aliasthis[lwr..upr]) */ Expression *e1 = se->copy(); ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident); UnaExp *ue = (UnaExp *)copy(); if (!ue->att1 && se->e1->type->checkAliasThisRec()) ue->att1 = se->e1->type; ue->e1 = e1; if (Expression *e = ue->trySemantic(sc)) return e; } att1 = NULL; } } #endif e1 = e1->semantic(sc); e1 = resolveProperties(sc, e1); AggregateDeclaration *ad = isAggregate(e1->type); if (ad) { Dsymbol *fd = NULL; #if 1 // Old way, kept for compatibility with D1 if (op != TOKpreplusplus && op != TOKpreminusminus) { fd = search_function(ad, opId()); if (fd) { if (op == TOKarray) { /* Rewrite op e1[arguments] as: * e1.fd(arguments) */ Expression *e = new DotIdExp(loc, e1, fd->ident); ArrayExp *ae = (ArrayExp *)this; e = new CallExp(loc, e, ae->arguments); e = e->semantic(sc); return e; } else { // Rewrite +e1 as e1.add() return build_overload(loc, sc, e1, NULL, fd); } } } #endif #if DMDV2 /* Rewrite as: * e1.opUnary!("+")(); */ fd = search_function(ad, Id::opUnary); if (fd) { Objects *tiargs = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, tiargs); e = new CallExp(loc, e); e = e->semantic(sc); return e; } // Didn't find it. Forward to aliasthis if (ad->aliasthis && this->e1->type != att1) { /* Rewrite op(e1) as: * op(e1.aliasthis) */ //printf("att una %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars()); Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); UnaExp *ue = (UnaExp *)copy(); if (!ue->att1 && this->e1->type->checkAliasThisRec()) ue->att1 = this->e1->type; ue->e1 = e1; return ue->trySemantic(sc); } #endif } return NULL; }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); if (needInterpret) sc = sc->startCTFE(); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (needInterpret) sc = sc->endCTFE(); if (exp->op == TOKerror) return new ErrorInitializer(); unsigned int olderrors = global.errors; if (needInterpret) { // If the result will be implicitly cast, move the cast into CTFE // to avoid premature truncation of polysemous types. // eg real [] x = [1.1, 2.2]; should use real precision. if (exp->implicitConvTo(t)) { exp = exp->implicitCastTo(sc, t); } exp = exp->ctfeInterpret(); } else { exp = exp->optimize(WANTvalue); } if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages if (exp->type->ty == Ttuple && ((TypeTuple *)exp->type)->arguments->dim == 0) { Type *et = exp->type; exp = new TupleExp(exp->loc, new Expressions()); exp->type = et; } if (exp->op == TOKtype) { exp->error("initializer must be an expression, not '%s'", exp->toChars()); return new ErrorInitializer(); } // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(exp)) { exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars()); return new ErrorInitializer(); } Type *tb = t->toBasetype(); Type *ti = exp->type->toBasetype(); if (exp->op == TOKtuple && expandTuples && !exp->implicitConvTo(t)) return new ExpInitializer(loc, exp); /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; * Allow this by doing an explicit cast, which will lengthen the string * literal. */ if (exp->op == TOKstring && tb->ty == Tsarray) { StringExp *se = (StringExp *)exp; Type *typeb = se->type->toBasetype(); TY tynto = tb->nextOf()->ty; if (!se->committed && (typeb->ty == Tarray || typeb->ty == Tsarray) && (tynto == Tchar || tynto == Twchar || tynto == Tdchar) && se->length((int)tb->nextOf()->size()) < ((TypeSArray *)tb)->dim->toInteger()) { exp = se->castTo(sc, t); goto L1; } } // Look for implicit constructor call if (tb->ty == Tstruct && !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) && !exp->implicitConvTo(t)) { StructDeclaration *sd = ((TypeStruct *)tb)->sym; if (sd->ctor) { // Rewrite as S().ctor(exp) Expression *e; e = new StructLiteralExp(loc, sd, NULL); e = new DotIdExp(loc, e, Id::ctor); e = new CallExp(loc, e, exp); e = e->semantic(sc); if (needInterpret) exp = e->ctfeInterpret(); else exp = e->optimize(WANTvalue); } } // Look for the case of statically initializing an array // with a single member. if (tb->ty == Tsarray && !tb->nextOf()->equals(ti->toBasetype()->nextOf()) && exp->implicitConvTo(tb->nextOf()) ) { /* If the variable is not actually used in compile time, array creation is * redundant. So delay it until invocation of toExpression() or toDt(). */ t = tb->nextOf(); } if (exp->implicitConvTo(t)) { exp = exp->implicitCastTo(sc, t); } else { // Look for mismatch of compile-time known length to emit // better diagnostic message, as same as AssignExp::semantic. if (tb->ty == Tsarray && exp->implicitConvTo(tb->nextOf()->arrayOf()) > MATCHnomatch) { uinteger_t dim1 = ((TypeSArray *)tb)->dim->toInteger(); uinteger_t dim2 = dim1; if (exp->op == TOKarrayliteral) { ArrayLiteralExp *ale = (ArrayLiteralExp *)exp; dim2 = ale->elements ? ale->elements->dim : 0; } else if (exp->op == TOKslice) { Type *tx = toStaticArrayType((SliceExp *)exp); if (tx) dim2 = ((TypeSArray *)tx)->dim->toInteger(); } if (dim1 != dim2) { exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2); exp = new ErrorExp(); } } exp = exp->implicitCastTo(sc, t); } L1: if (exp->op == TOKerror) return this; if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
void PragmaDeclaration::semantic(Scope *sc) { // Should be merged with PragmaStatement //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); if (ident == Id::msg) { if (args) { for (size_t i = 0; i < args->dim; i++) { Expression *e = (*args)[i]; e = e->semantic(sc); e = resolveProperties(sc, e); if (e->op != TOKerror && e->op != TOKtype) e = e->ctfeInterpret(); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); return; } StringExp *se = e->toString(); if (se) { fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); } else fprintf(stdmsg, "%s", e->toChars()); } fprintf(stdmsg, "\n"); } goto Lnodecl; } else if (ident == Id::lib) { if (!args || args->dim != 1) error("string expected for library name"); else { Expression *e = (*args)[0]; e = e->semantic(sc); e = resolveProperties(sc, e); e = e->ctfeInterpret(); (*args)[0] = e; if (e->op == TOKerror) goto Lnodecl; StringExp *se = e->toString(); if (!se) error("string expected for library name, not '%s'", e->toChars()); else if (global.params.verbose) { char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; printf("library %s\n", name); mem.free(name); } } goto Lnodecl; } #ifdef IN_GCC else if (ident == Id::GNU_asm) { if (! args || args->dim != 2) error("identifier and string expected for asm name"); else { Expression *e; Declaration *d = NULL; StringExp *s = NULL; e = (*args)[0]; e = e->semantic(sc); if (e->op == TOKvar) { d = ((VarExp *)e)->var; if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) d = NULL; } if (!d) error("first argument of GNU_asm must be a function or variable declaration"); e = (*args)[1]; e = e->semantic(sc); e = resolveProperties(sc, e); e = e->ctfeInterpret(); e = e->toString(); if (e && ((StringExp *)e)->sz == 1) s = ((StringExp *)e); else error("second argument of GNU_asm must be a character string"); if (d && s) d->c_ident = Lexer::idPool((char*) s->string); } goto Lnodecl; } #endif #if DMDV2 else if (ident == Id::startaddress) { if (!args || args->dim != 1) error("function name expected for start address"); else { Expression *e = (*args)[0]; e = e->semantic(sc); e = resolveProperties(sc, e); e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) error("function name expected for start address, not '%s'", e->toChars()); } goto Lnodecl; } #endif #if TARGET_NET else if (ident == Lexer::idPool("assembly")) { } #endif // TARGET_NET else if (global.params.ignoreUnsupportedPragmas) { if (global.params.verbose) { /* Print unrecognized pragmas */ printf("pragma %s", ident->toChars()); if (args) { for (size_t i = 0; i < args->dim; i++) { Expression *e = (*args)[i]; e = e->semantic(sc); e = resolveProperties(sc, e); e = e->ctfeInterpret(); if (i == 0) printf(" ("); else printf(","); printf("%s", e->toChars()); } if (args->dim) printf(")"); } printf("\n"); } goto Lnodecl; } else error("unrecognized pragma(%s)", ident->toChars()); Ldecl: if (decl) { for (size_t i = 0; i < decl->dim; i++) { Dsymbol *s = (*decl)[i]; s->semantic(sc); } } return; Lnodecl: if (decl) { error("pragma is missing closing ';'"); goto Ldecl; // do them anyway, to avoid segfaults. } }
Initializer *ExpInitializer::inferType(Scope *sc, Type *tx) { //printf("ExpInitializer::inferType() %s\n", toChars()); exp = ::inferType(exp, tx); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (tx) { Type *tb = tx->toBasetype(); Type *ti = exp->type->toBasetype(); // Look for implicit constructor call if (tb->ty == Tstruct && !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) && !exp->implicitConvTo(tx)) { StructDeclaration *sd = ((TypeStruct *)tb)->sym; if (sd->ctor) { // Rewrite as S().ctor(exp) Expression *e; e = new StructLiteralExp(loc, sd, NULL); e = new DotIdExp(loc, e, Id::ctor); e = new CallExp(loc, e, exp); e = e->semantic(sc); exp = e->optimize(WANTvalue); } } } if (exp->op == TOKimport) { ScopeExp *se = (ScopeExp *)exp; TemplateInstance *ti = se->sds->isTemplateInstance(); if (ti && ti->semanticRun == PASSsemantic && !ti->aliasdecl) se->error("cannot infer type from %s %s, possible circular dependency", se->sds->kind(), se->toChars()); else se->error("cannot infer type from %s %s", se->sds->kind(), se->toChars()); return new ErrorInitializer(); } // Give error for overloaded function addresses if (exp->op == TOKsymoff) { SymOffExp *se = (SymOffExp *)exp; if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) { exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); return new ErrorInitializer(); } } if (exp->op == TOKdelegate) { DelegateExp *se = (DelegateExp *)exp; if (se->hasOverloads && se->func->isFuncDeclaration() && !se->func->isFuncDeclaration()->isUnique()) { exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); return new ErrorInitializer(); } } if (exp->op == TOKaddress) { AddrExp *ae = (AddrExp *)exp; if (ae->e1->op == TOKoverloadset) { exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); return new ErrorInitializer(); } } if (exp->op == TOKerror) return new ErrorInitializer(); if (!exp->type) return new ErrorInitializer(); return this; }
Initializer *ArrayInitializer::inferType(Scope *sc, Type *tx) { //printf("ArrayInitializer::inferType() %s\n", toChars()); Expressions *keys = NULL; Expressions *values; if (tx ? (tx->ty == Taarray || tx->ty != Tarray && tx->ty != Tsarray && isAssociativeArray()) : isAssociativeArray()) { Type *tidx = NULL; Type *tval = NULL; if (tx && tx->ty == Taarray) { tidx = ((TypeAArray *)tx)->index; tval = ((TypeAArray *)tx)->next; } keys = new Expressions(); keys->setDim(value.dim); values = new Expressions(); values->setDim(value.dim); for (size_t i = 0; i < value.dim; i++) { Expression *e = index[i]; if (!e) goto Lno; if (tidx) { e = ::inferType(e, tidx); e = e->semantic(sc); e = resolveProperties(sc, e); if (tidx->deco) // tidx may be partial type e = e->implicitCastTo(sc, tidx); } (*keys)[i] = e; Initializer *iz = value[i]; if (!iz) goto Lno; iz = iz->inferType(sc, tval); if (iz->isErrorInitializer()) return iz; assert(iz->isExpInitializer()); (*values)[i] = ((ExpInitializer *)iz)->exp; assert((*values)[i]->op != TOKerror); } Expression *e = new AssocArrayLiteralExp(loc, keys, values); ExpInitializer *ei = new ExpInitializer(loc, e); return ei->inferType(sc, tx); } else { Type *tn = NULL; if (tx && (tx->ty == Tarray || tx->ty == Tsarray)) tn = ((TypeNext *)tx)->next; Expressions *elements = new Expressions(); elements->setDim(value.dim); elements->zero(); for (size_t i = 0; i < value.dim; i++) { assert(!index[i]); // already asserted by isAssociativeArray() Initializer *iz = value[i]; if (!iz) goto Lno; iz = iz->inferType(sc, tn); if (iz->isErrorInitializer()) return iz; assert(iz->isExpInitializer()); (*elements)[i] = ((ExpInitializer *)iz)->exp; assert((*elements)[i]->op != TOKerror); } Expression *e = new ArrayLiteralExp(loc, elements); ExpInitializer *ei = new ExpInitializer(loc, e); return ei->inferType(sc, tx); } Lno: if (keys) { delete keys; delete values; error(loc, "not an associative array initializer"); } else { error(loc, "cannot infer type from array initializer"); } return new ErrorInitializer(); }
void VarDeclaration::semantic(Scope *sc) { #if 0 printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); printf(" type = %s\n", type ? type->toChars() : "null"); printf(" stc = x%x\n", sc->stc); printf(" storage_class = x%x\n", storage_class); printf("linkage = %d\n", sc->linkage); //if (strcmp(toChars(), "mul") == 0) halt(); #endif if (scope) { sc = scope; scope = NULL; } storage_class |= sc->stc; if (storage_class & STCextern && init) error("extern symbols cannot have initializers"); AggregateDeclaration *ad = isThis(); if (ad) storage_class |= ad->storage_class & STC_TYPECTOR; /* If auto type inference, do the inference */ int inferred = 0; if (!type) { inuse++; type = init->inferType(sc); type = type->semantic(loc, sc); inuse--; inferred = 1; /* This is a kludge to support the existing syntax for RAII * declarations. */ storage_class &= ~STCauto; originalType = type; } else { if (!originalType) originalType = type; type = type->semantic(loc, sc); } //printf(" semantic type = %s\n", type ? type->toChars() : "null"); type->checkDeprecated(loc, sc); linkage = sc->linkage; this->parent = sc->parent; //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); protection = sc->protection; //printf("sc->stc = %x\n", sc->stc); //printf("storage_class = x%x\n", storage_class); #if DMDV2 if (storage_class & STCgshared && global.params.safe && !sc->module->safe) { error("__gshared not allowed in safe mode; use shared"); } #endif Dsymbol *parent = toParent(); FuncDeclaration *fd = parent->isFuncDeclaration(); Type *tb = type->toBasetype(); if (tb->ty == Tvoid && !(storage_class & STClazy)) { error("voids have no value"); type = Type::terror; tb = type; } if (tb->ty == Tfunction) { error("cannot be declared to be a function"); type = Type::terror; tb = type; } if (tb->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tb; if (!ts->sym->members) { error("no definition of struct %s", ts->toChars()); } } if ((storage_class & STCauto) && !inferred) error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?"); if (tb->ty == Ttuple) { /* Instead, declare variables for each of the tuple elements * and add those. */ TypeTuple *tt = (TypeTuple *)tb; size_t nelems = Parameter::dim(tt->arguments); Objects *exps = new Objects(); exps->setDim(nelems); Expression *ie = init ? init->toExpression() : NULL; for (size_t i = 0; i < nelems; i++) { Parameter *arg = Parameter::getNth(tt->arguments, i); OutBuffer buf; buf.printf("_%s_field_%zu", ident->toChars(), i); buf.writeByte(0); const char *name = (const char *)buf.extractData(); Identifier *id = Lexer::idPool(name); Expression *einit = ie; if (ie && ie->op == TOKtuple) { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; } Initializer *ti = init; if (einit) { ti = new ExpInitializer(einit->loc, einit); } VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); v->semantic(sc); #if !IN_LLVM // removed for LDC since TupleDeclaration::toObj already creates the fields; // adding them to the scope again leads to duplicates if (sc->scopesym) { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); if (sc->scopesym->members) sc->scopesym->members->push(v); } #endif Expression *e = new DsymbolExp(loc, v); exps->data[i] = e; } TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); v2->isexp = 1; aliassym = v2; return; } if (storage_class & STCconst && !init && !fd) // Initialize by constructor only storage_class = (storage_class & ~STCconst) | STCctorinit; if (isConst()) { } else if (isStatic()) { } else if (isSynchronized()) { error("variable %s cannot be synchronized", toChars()); } else if (isOverride()) { error("override cannot be applied to variable"); } else if (isAbstract()) { error("abstract cannot be applied to variable"); } else if (storage_class & STCtemplateparameter) { } else if (storage_class & STCctfe) { } else { AggregateDeclaration *aad = sc->anonAgg; if (!aad) aad = parent->isAggregateDeclaration(); if (aad) { #if DMDV2 assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); if (storage_class & (STCconst | STCimmutable) && init) { if (!type->toBasetype()->isTypeBasic()) storage_class |= STCstatic; } else #endif aad->addField(sc, this); } InterfaceDeclaration *id = parent->isInterfaceDeclaration(); if (id) { error("field not allowed in interface"); } /* Templates cannot add fields to aggregates */ TemplateInstance *ti = parent->isTemplateInstance(); if (ti) { // Take care of nested templates while (1) { TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); if (!ti2) break; ti = ti2; } // If it's a member template AggregateDeclaration *ad2 = ti->tempdecl->isMember(); if (ad2 && storage_class != STCundefined) { error("cannot use template to add field to aggregate '%s'", ad2->toChars()); } } } #if DMDV2 if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && ident != Id::This) { error("only parameters or foreach declarations can be ref"); } #endif if (type->isscope() && !noscope) { if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) { error("globals, statics, fields, ref and out parameters cannot be auto"); } if (!(storage_class & STCscope)) { if (!(storage_class & STCparameter) && ident != Id::withSym) error("reference to scope class must be scope"); } } enum TOK op = TOKconstruct; if (!init && !sc->inunion && !isStatic() && !isConst() && fd && !(storage_class & (STCfield | STCin | STCforeach)) && type->size() != 0) { // Provide a default initializer //printf("Providing default initializer for '%s'\n", toChars()); if (type->ty == Tstruct && ((TypeStruct *)type)->sym->zeroInit == 1) { /* If a struct is all zeros, as a special case * set it's initializer to the integer 0. * In AssignExp::toElem(), we check for this and issue * a memset() to initialize the struct. * Must do same check in interpreter. */ Expression *e = new IntegerExp(loc, 0, Type::tint32); Expression *e1; e1 = new VarExp(loc, this); e = new AssignExp(loc, e1, e); e->op = TOKconstruct; e->type = e1->type; // don't type check this, it would fail init = new ExpInitializer(loc, e); return; } else if (type->ty == Ttypedef) { TypeTypedef *td = (TypeTypedef *)type; if (td->sym->init) { init = td->sym->init; ExpInitializer *ie = init->isExpInitializer(); if (ie) // Make copy so we can modify it init = new ExpInitializer(ie->loc, ie->exp); } else init = getExpInitializer(); } else { init = getExpInitializer(); } // Default initializer is always a blit op = TOKblit; } if (init) { sc = sc->push(); sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); ArrayInitializer *ai = init->isArrayInitializer(); if (ai && tb->ty == Taarray) { init = ai->toAssocArrayInitializer(); } StructInitializer *si = init->isStructInitializer(); ExpInitializer *ei = init->isExpInitializer(); // See if initializer is a NewExp that can be allocated on the stack if (ei && isScope() && ei->exp->op == TOKnew) { NewExp *ne = (NewExp *)ei->exp; if (!(ne->newargs && ne->newargs->dim)) { ne->onstack = 1; onstack = 1; if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) onstack = 2; } } // If inside function, there is no semantic3() call if (sc->func) { // If local variable, use AssignExp to handle all the various // possibilities. if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) { //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); if (!ei) { Expression *e = init->toExpression(); if (!e) { init = init->semantic(sc, type, 0); // Don't need to interpret e = init->toExpression(); if (!e) { error("is not a static and cannot have static initializer"); return; } } ei = new ExpInitializer(init->loc, e); init = ei; } Expression *e1 = new VarExp(loc, this); Type *t = type->toBasetype(); if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) { ei->exp = ei->exp->semantic(sc); if (!ei->exp->implicitConvTo(type)) { dinteger_t dim = ((TypeSArray *)t)->dim->toInteger(); // If multidimensional static array, treat as one large array while (1) { t = t->nextOf()->toBasetype(); if (t->ty != Tsarray) break; dim *= ((TypeSArray *)t)->dim->toInteger(); e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); } } e1 = new SliceExp(loc, e1, NULL, NULL); } else if (t->ty == Tstruct) { ei->exp = ei->exp->semantic(sc); ei->exp = resolveProperties(sc, ei->exp); StructDeclaration *sd = ((TypeStruct *)t)->sym; #if DMDV2 /* Look to see if initializer is a call to the constructor */ if (sd->ctor && // there are constructors ei->exp->type->ty == Tstruct && // rvalue is the same struct ((TypeStruct *)ei->exp->type)->sym == sd && ei->exp->op == TOKstar) { /* Look for form of constructor call which is: * *__ctmp.ctor(arguments...) */ PtrExp *pe = (PtrExp *)ei->exp; if (pe->e1->op == TOKcall) { CallExp *ce = (CallExp *)pe->e1; if (ce->e1->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)ce->e1; if (dve->var->isCtorDeclaration()) { /* It's a constructor call, currently constructing * a temporary __ctmp. */ /* Before calling the constructor, initialize * variable with a bit copy of the default * initializer */ Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); e->op = TOKblit; e->type = t; ei->exp = new CommaExp(loc, e, ei->exp); /* Replace __ctmp being constructed with e1 */ dve->e1 = e1; return; } } } } #endif if (!ei->exp->implicitConvTo(type)) { /* Look for opCall * See bugzilla 2702 for more discussion */ Type *ti = ei->exp->type->toBasetype(); // Don't cast away invariant or mutability in initializer if (search_function(sd, Id::call) && /* Initializing with the same type is done differently */ !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) { // Rewrite as e1.call(arguments) Expression * eCall = new DotIdExp(loc, e1, Id::call); ei->exp = new CallExp(loc, eCall, ei->exp); } } } ei->exp = new AssignExp(loc, e1, ei->exp); ei->exp->op = TOKconstruct; canassign++; ei->exp = ei->exp->semantic(sc); canassign--; ei->exp->optimize(WANTvalue); } else { init = init->semantic(sc, type, WANTinterpret); if (fd && isConst() && !isStatic()) { // Make it static storage_class |= STCstatic; } } } else if (isConst() || isFinal() || parent->isAggregateDeclaration()) { /* Because we may need the results of a const declaration in a * subsequent type, such as an array dimension, before semantic2() * gets ordinarily run, try to run semantic2() now. * Ignore failure. */ if (!global.errors && !inferred) { unsigned errors = global.startGagging(); Expression *e; Initializer *i2 = init; inuse++; if (ei) { e = ei->exp->syntaxCopy(); e = e->semantic(sc); e = e->implicitCastTo(sc, type); } else if (si || ai) { i2 = init->syntaxCopy(); i2 = i2->semantic(sc, type, WANTinterpret); } inuse--; if (global.endGagging(errors)) // if errors happened { #if DMDV2 /* Save scope for later use, to try again */ scope = new Scope(*sc); scope->setNoFree(); #endif } else if (ei) { if (isDataseg() || (storage_class & STCmanifest)) e = e->optimize(WANTvalue | WANTinterpret); else e = e->optimize(WANTvalue); switch (e->op) { case TOKint64: case TOKfloat64: case TOKstring: case TOKarrayliteral: case TOKassocarrayliteral: case TOKstructliteral: case TOKnull: ei->exp = e; // no errors, keep result break; default: #if DMDV2 /* Save scope for later use, to try again */ scope = new Scope(*sc); scope->setNoFree(); #endif break; } } else init = i2; // no errors, keep result } } sc = sc->pop(); } }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (exp->op == TOKerror) return this; int olderrors = global.errors; if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages if (exp->op == TOKtype) exp->error("initializer must be an expression, not '%s'", exp->toChars()); // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(exp)) { exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars()); return this; } Type *tb = t->toBasetype(); if (exp->op == TOKtuple && expandTuples && !exp->implicitConvTo(t)) return new ExpInitializer(loc, exp); /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; * Allow this by doing an explicit cast, which will lengthen the string * literal. */ if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray) { StringExp *se = (StringExp *)exp; if (!se->committed && se->type->ty == Tsarray && ((TypeSArray *)se->type)->dim->toInteger() < ((TypeSArray *)t)->dim->toInteger()) { exp = se->castTo(sc, t); goto L1; } } // Look for the case of statically initializing an array // with a single member. if (tb->ty == Tsarray && !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) && exp->implicitConvTo(tb->nextOf()) ) { t = tb->nextOf(); } exp = exp->implicitCastTo(sc, t); if (exp->op == TOKerror) return this; L1: if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
/*************************************** * Fit elements[] to the corresponding type of field[]. * Input: * loc * sc * elements The explicit arguments that given to construct object. * stype The constructed object type. * Returns false if any errors occur. * Otherwise, returns true and elements[] are rewritten for the output. */ bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype) { if (!elements) return true; size_t nfields = fields.dim - isNested(); size_t offset = 0; for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (!e) continue; e = resolveProperties(sc, e); if (i >= nfields) { if (i == fields.dim - 1 && isNested() && e->op == TOKnull) { // CTFE sometimes creates null as hidden pointer; we'll allow this. continue; } ::error(loc, "more initializers than fields (%d) of %s", nfields, toChars()); return false; } VarDeclaration *v = fields[i]; if (v->offset < offset) { ::error(loc, "overlapping initialization for %s", v->toChars()); return false; } offset = (unsigned)(v->offset + v->type->size()); Type *t = v->type; if (stype) t = t->addMod(stype->mod); Type *origType = t; Type *tb = t->toBasetype(); /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; * Allow this by doing an explicit cast, which will lengthen the string * literal. */ if (e->op == TOKstring && tb->ty == Tsarray) { StringExp *se = (StringExp *)e; Type *typeb = se->type->toBasetype(); TY tynto = tb->nextOf()->ty; if (!se->committed && (typeb->ty == Tarray || typeb->ty == Tsarray) && (tynto == Tchar || tynto == Twchar || tynto == Tdchar) && se->length((int)tb->nextOf()->size()) < ((TypeSArray *)tb)->dim->toInteger()) { e = se->castTo(sc, t); goto L1; } } while (!e->implicitConvTo(t) && tb->ty == Tsarray) { /* Static array initialization, as in: * T[3][5] = e; */ t = tb->nextOf(); tb = t->toBasetype(); } if (!e->implicitConvTo(t)) t = origType; // restore type for better diagnostic e = e->implicitCastTo(sc, t); L1: if (e->op == TOKerror) return false; (*elements)[i] = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e); } return true; }