Expression *semanticTraits(TraitsExp *e, Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", e->toChars()); #endif if (e->ident != Id::compiles && e->ident != Id::isSame && e->ident != Id::identifier && e->ident != Id::getProtection) { if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) return new ErrorExp(); } size_t dim = e->args ? e->args->dim : 0; if (e->ident == Id::isArithmetic) { return isTypeX(e, &isTypeArithmetic); } else if (e->ident == Id::isFloating) { return isTypeX(e, &isTypeFloating); } else if (e->ident == Id::isIntegral) { return isTypeX(e, &isTypeIntegral); } else if (e->ident == Id::isScalar) { return isTypeX(e, &isTypeScalar); } else if (e->ident == Id::isUnsigned) { return isTypeX(e, &isTypeUnsigned); } else if (e->ident == Id::isAssociativeArray) { return isTypeX(e, &isTypeAssociativeArray); } else if (e->ident == Id::isStaticArray) { return isTypeX(e, &isTypeStaticArray); } else if (e->ident == Id::isAbstractClass) { return isTypeX(e, &isTypeAbstractClass); } else if (e->ident == Id::isFinalClass) { return isTypeX(e, &isTypeFinalClass); } else if (e->ident == Id::isTemplate) { return isSymbolX(e, &isTemplate); } else if (e->ident == Id::isPOD) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) { e->error("type expected as second argument of __traits %s instead of %s", e->ident->toChars(), o->toChars()); goto Lfalse; } Type *tb = t->baseElemOf(); if (tb->ty == Tstruct && ((sd = (StructDeclaration *)(((TypeStruct *)tb)->sym)) != NULL)) { if (sd->isPOD()) goto Ltrue; else goto Lfalse; } goto Ltrue; } else if (e->ident == Id::isNested) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; if (!s) { } else if ((a = s->isAggregateDeclaration()) != NULL) { if (a->isNested()) goto Ltrue; else goto Lfalse; } else if ((f = s->isFuncDeclaration()) != NULL) { if (f->isNested()) goto Ltrue; else goto Lfalse; } e->error("aggregate or function expected instead of '%s'", o->toChars()); goto Lfalse; } else if (e->ident == Id::isAbstractFunction) { return isFuncX(e, &isFuncAbstractFunction); } else if (e->ident == Id::isVirtualFunction) { return isFuncX(e, &isFuncVirtualFunction); } else if (e->ident == Id::isVirtualMethod) { return isFuncX(e, &isFuncVirtualMethod); } else if (e->ident == Id::isFinalFunction) { return isFuncX(e, &isFuncFinalFunction); } else if (e->ident == Id::isOverrideFunction) { return isFuncX(e, &isFuncOverrideFunction); } else if (e->ident == Id::isStaticFunction) { return isFuncX(e, &isFuncStaticFunction); } else if (e->ident == Id::isRef) { return isDeclX(e, &isDeclRef); } else if (e->ident == Id::isOut) { return isDeclX(e, &isDeclOut); } else if (e->ident == Id::isLazy) { return isDeclX(e, &isDeclLazy); } else if (e->ident == Id::identifier) { // Get identifier for symbol as a string literal /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that * a symbol should not be folded to a constant. * Bit 1 means don't convert Parameter to Type if Parameter has an identifier */ if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2)) return new ErrorExp(); if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Parameter *po = isParameter(o); Identifier *id; if (po) { id = po->ident; assert(id); } else { Dsymbol *s = getDsymbol(o); if (!s || !s->ident) { e->error("argument %s has no identifier", o->toChars()); goto Lfalse; } id = s->ident; } StringExp *se = new StringExp(e->loc, id->toChars()); return se->semantic(sc); } else if (e->ident == Id::getProtection) { if (dim != 1) goto Ldimerror; Scope *sc2 = sc->push(); sc2->flags = sc->flags | SCOPEnoaccesscheck; bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1); sc2->pop(); if (!ok) return new ErrorExp(); RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { if (!isError(o)) e->error("argument %s has no protection", o->toChars()); goto Lfalse; } if (s->scope) s->semantic(s->scope); const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names) assert(protName); StringExp *se = new StringExp(e->loc, (char *) protName); return se->semantic(sc); } else if (e->ident == Id::parent) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (s) { if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 s = fd->toAliasFunc(); if (!s->isImport()) // Bugzilla 8922 s = s->toParent(); } if (!s || s->isImport()) { e->error("argument %s has no parent", o->toChars()); goto Lfalse; } if (FuncDeclaration *f = s->isFuncDeclaration()) { if (TemplateDeclaration *td = getFuncTemplateDecl(f)) { if (td->overroot) // if not start of overloaded list of TemplateDeclaration's td = td->overroot; // then get the start Expression *ex = new TemplateExp(e->loc, td, f); ex = ex->semantic(sc); return ex; } if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration()) { // Directly translate to VarExp instead of FuncExp Expression *ex = new VarExp(e->loc, fld, 1); return ex->semantic(sc); } } return (new DsymbolExp(e->loc, s))->semantic(sc); } else if (e->ident == Id::hasMember || e->ident == Id::getMember || e->ident == Id::getOverloads || e->ident == Id::getVirtualMethods || e->ident == Id::getVirtualFunctions) { if (dim != 2) goto Ldimerror; RootObject *o = (*e->args)[0]; Expression *ex = isExpression((*e->args)[1]); if (!ex) { e->error("expression expected as second argument of __traits %s", e->ident->toChars()); goto Lfalse; } ex = ex->ctfeInterpret(); StringExp *se = ex->toStringExp(); if (!se || se->length() == 0) { e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars()); goto Lfalse; } se = se->toUTF8(sc); if (se->sz != 1) { e->error("string must be chars"); goto Lfalse; } Identifier *id = Identifier::idPool((char *)se->string); /* Prefer dsymbol, because it might need some runtime contexts. */ Dsymbol *sym = getDsymbol(o); if (sym) { ex = new DsymbolExp(e->loc, sym); ex = new DotIdExp(e->loc, ex, id); } else if (Type *t = isType(o)) ex = typeDotIdExp(e->loc, t, id); else if (Expression *ex2 = isExpression(o)) ex = new DotIdExp(e->loc, ex2, id); else { e->error("invalid first argument"); goto Lfalse; } if (e->ident == Id::hasMember) { if (sym) { Dsymbol *sm = sym->search(e->loc, id); if (sm) goto Ltrue; } /* Take any errors as meaning it wasn't found */ Scope *sc2 = sc->push(); ex = ex->trySemantic(sc2); sc2->pop(); if (!ex) goto Lfalse; else goto Ltrue; } else if (e->ident == Id::getMember) { ex = ex->semantic(sc); return ex; } else if (e->ident == Id::getVirtualFunctions || e->ident == Id::getVirtualMethods || e->ident == Id::getOverloads) { unsigned errors = global.errors; Expression *eorig = ex; ex = ex->semantic(sc); if (errors < global.errors) e->error("%s cannot be resolved", eorig->toChars()); /* Create tuple of functions of ex */ //ex->print(); Expressions *exps = new Expressions(); FuncDeclaration *f; if (ex->op == TOKvar) { VarExp *ve = (VarExp *)ex; f = ve->var->isFuncDeclaration(); ex = NULL; } else if (ex->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)ex; f = dve->var->isFuncDeclaration(); if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis) ex = NULL; else ex = dve->e1; } else f = NULL; Ptrait p; p.exps = exps; p.e1 = ex; p.ident = e->ident; overloadApply(f, &p, &fptraits); TupleExp *tup = new TupleExp(e->loc, exps); return tup->semantic(sc); } else assert(0); } else if (e->ident == Id::classInstanceSize) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) { e->error("first argument is not a class"); goto Lfalse; } if (cd->sizeok == SIZEOKnone) { if (cd->scope) cd->semantic(cd->scope); } if (cd->sizeok != SIZEOKdone) { e->error("%s %s is forward referenced", cd->kind(), cd->toChars()); goto Lfalse; } return new IntegerExp(e->loc, cd->structsize, Type::tsize_t); } else if (e->ident == Id::getAliasThis) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *ad; if (!s || (ad = s->isAggregateDeclaration()) == NULL) { e->error("argument is not an aggregate type"); goto Lfalse; } Expressions *exps = new Expressions(); if (ad->aliasthis) exps->push(new StringExp(e->loc, ad->aliasthis->ident->toChars())); Expression *ex = new TupleExp(e->loc, exps); ex = ex->semantic(sc); return ex; } else if (e->ident == Id::getAttributes) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { #if 0 Expression *x = isExpression(o); Type *t = isType(o); if (x) printf("e = %s %s\n", Token::toChars(x->op), x->toChars()); if (t) printf("t = %d %s\n", t->ty, t->toChars()); #endif e->error("first argument is not a symbol"); goto Lfalse; } if (s->isImport()) { s = s->isImport()->mod; } //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->scope); UserAttributeDeclaration *udad = s->userAttribDecl; TupleExp *tup = new TupleExp(e->loc, udad ? udad->getAttributes() : new Expressions()); return tup->semantic(sc); } else if (e->ident == Id::getFunctionAttributes) { /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); Type *t = isType(o); TypeFunction *tf = NULL; if (s) { if (FuncDeclaration *f = s->isFuncDeclaration()) t = f->type; else if (VarDeclaration *v = s->isVarDeclaration()) t = v->type; } if (t) { if (t->ty == Tfunction) tf = (TypeFunction *)t; else if (t->ty == Tdelegate) tf = (TypeFunction *)t->nextOf(); else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) tf = (TypeFunction *)t->nextOf(); } if (!tf) { e->error("first argument is not a function"); goto Lfalse; } Expressions *mods = new Expressions(); PushAttributes pa; pa.mods = mods; tf->modifiersApply(&pa, &PushAttributes::fp); tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem); TupleExp *tup = new TupleExp(e->loc, mods); return tup->semantic(sc); } else if (e->ident == Id::allMembers || e->ident == Id::derivedMembers) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sds; if (!s) { e->error("argument has no members"); goto Lfalse; } Import *import; if ((import = s->isImport()) != NULL) { // Bugzilla 9692 sds = import->mod; } else if ((sds = s->isScopeDsymbol()) == NULL) { e->error("%s %s has no members", s->kind(), s->toChars()); goto Lfalse; } // use a struct as local function struct PushIdentsDg { static int dg(void *ctx, size_t n, Dsymbol *sm) { if (!sm) return 1; //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { if (sm->ident != Id::ctor && sm->ident != Id::dtor && sm->ident != Id::_postblit && memcmp(sm->ident->string, "__", 2) == 0) { return 0; } //printf("\t%s\n", sm->ident->toChars()); Identifiers *idents = (Identifiers *)ctx; /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) { Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. assert(strcmp(id->toChars(), sm->ident->toChars()) != 0); #endif } idents->push(sm->ident); } else { EnumDeclaration *ed = sm->isEnumDeclaration(); if (ed) { ScopeDsymbol::foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx); } } return 0; } }; Identifiers *idents = new Identifiers; ScopeDsymbol::foreach(sc, sds->members, &PushIdentsDg::dg, idents); ClassDeclaration *cd = sds->isClassDeclaration(); if (cd && e->ident == Id::allMembers) { if (cd->scope) cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference struct PushBaseMembers { static void dg(ClassDeclaration *cd, Identifiers *idents) { for (size_t i = 0; i < cd->baseclasses->dim; i++) { ClassDeclaration *cb = (*cd->baseclasses)[i]->base; assert(cb); ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents); if (cb->baseclasses->dim) dg(cb, idents); } } }; PushBaseMembers::dg(cd, idents); } // Turn Identifiers into StringExps reusing the allocated array assert(sizeof(Expressions) == sizeof(Identifiers)); Expressions *exps = (Expressions *)idents; for (size_t i = 0; i < idents->dim; i++) { Identifier *id = (*idents)[i]; StringExp *se = new StringExp(e->loc, id->toChars()); (*exps)[i] = se; } /* Making this a tuple is more flexible, as it can be statically unrolled. * To make an array literal, enclose __traits in [ ]: * [ __traits(allMembers, ...) ] */ Expression *ex = new TupleExp(e->loc, exps); ex = ex->semantic(sc); return ex; } else if (e->ident == Id::compiles) { /* Determine if all the objects - types, expressions, or symbols - * compile without error */ if (!dim) goto Lfalse; for (size_t i = 0; i < dim; i++) { unsigned errors = global.startGagging(); Scope *sc2 = sc->push(); sc2->tinst = NULL; sc2->minst = NULL; sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile; bool err = false; RootObject *o = (*e->args)[i]; Type *t = isType(o); Expression *ex = t ? t->toExpression() : isExpression(o); if (!ex && t) { Dsymbol *s; t->resolve(e->loc, sc2, &ex, &t, &s); if (t) { t->semantic(e->loc, sc2); if (t->ty == Terror) err = true; } else if (s && s->errors) err = true; } if (ex) { ex = ex->semantic(sc2); ex = resolvePropertiesOnly(sc2, ex); ex = ex->optimize(WANTvalue); if (sc2->func && sc2->func->type->ty == Tfunction) { TypeFunction *tf = (TypeFunction *)sc2->func->type; canThrow(ex, sc2->func, tf->isnothrow); } ex = checkGC(sc2, ex); if (ex->op == TOKerror) err = true; } sc2->pop(); if (global.endGagging(errors) || err) { goto Lfalse; } } goto Ltrue; } else if (e->ident == Id::isSame) { /* Determine if two symbols are the same */ if (dim != 2) goto Ldimerror; if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0)) return new ErrorExp(); RootObject *o1 = (*e->args)[0]; RootObject *o2 = (*e->args)[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); #if 0 printf("o1: %p\n", o1); printf("o2: %p\n", o2); if (!s1) { Expression *ea = isExpression(o1); if (ea) printf("%s\n", ea->toChars()); Type *ta = isType(o1); if (ta) printf("%s\n", ta->toChars()); goto Lfalse; } else printf("%s %s\n", s1->kind(), s1->toChars()); #endif if (!s1 && !s2) { Expression *ea1 = isExpression(o1); Expression *ea2 = isExpression(o2); if (ea1 && ea2) { if (ea1->equals(ea2)) goto Ltrue; } } if (!s1 || !s2) goto Lfalse; s1 = s1->toAlias(); s2 = s2->toAlias(); if (s1->isFuncAliasDeclaration()) s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc(); if (s2->isFuncAliasDeclaration()) s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc(); if (s1 == s2) goto Ltrue; else goto Lfalse; } else if (e->ident == Id::getUnitTests) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", o->toChars()); goto Lfalse; } Import *imp = s->isImport(); if (imp) // Bugzilla 10990 s = imp->mod; ScopeDsymbol* scope = s->isScopeDsymbol(); if (!scope) { e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", s->toChars(), s->kind()); goto Lfalse; } Expressions* unitTests = new Expressions(); Dsymbols* symbols = scope->members; if (global.params.useUnitTests && symbols) { // Should actually be a set AA* uniqueUnitTests = NULL; collectUnitTests(symbols, uniqueUnitTests, unitTests); } TupleExp *tup = new TupleExp(e->loc, unitTests); return tup->semantic(sc); } else if(e->ident == Id::getVirtualIndex) { if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; Dsymbol *s = getDsymbol(o); FuncDeclaration *fd; if (!s || (fd = s->isFuncDeclaration()) == NULL) { e->error("first argument to __traits(getVirtualIndex) must be a function"); goto Lfalse; } fd = fd->toAliasFunc(); // Neccessary to support multiple overloads. return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t); } else if (e->ident == Id::getPointerBitmap) { return pointerBitmap(e); } else { if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars)) e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub); else e->error("unrecognized trait '%s'", e->ident->toChars()); goto Lfalse; } return NULL; Ldimerror: e->error("wrong number of arguments %d", (int)dim); goto Lfalse; Lfalse: return new IntegerExp(e->loc, 0, Type::tbool); Ltrue: return new IntegerExp(e->loc, 1, Type::tbool); }
Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); t = t->toBasetype(); if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct) t = t->nextOf()->toBasetype(); if (t->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)t)->sym; if (sd->ctor) { error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", sd->kind(), sd->toChars(), sd->toChars()); return new ErrorInitializer(); } sd->size(loc); if (sd->sizeok != SIZEOKdone) return new ErrorInitializer(); size_t nfields = sd->fields.dim - sd->isNested(); //expandTuples for non-identity arguments? Expressions *elements = new Expressions(); elements->setDim(nfields); for (size_t i = 0; i < elements->dim; i++) (*elements)[i] = NULL; // Run semantic for explicitly given initializers // TODO: this part is slightly different from StructLiteralExp::semantic. bool errors = false; for (size_t fieldi = 0, i = 0; i < field.dim; i++) { if (Identifier *id = field[i]) { Dsymbol *s = sd->search(loc, id); if (!s) { s = sd->search_correct(id); if (s) error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", id->toChars(), sd->toChars(), s->kind(), s->toChars()); else error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); return new ErrorInitializer(); } s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { error(loc, "%s.%s is not a per-instance initializable field", sd->toChars(), s->toChars()); return new ErrorInitializer(); } if (s == sd->fields[fieldi]) break; } } else if (fieldi >= nfields) { error(loc, "too many initializers for %s", sd->toChars()); return new ErrorInitializer(); } VarDeclaration *vd = sd->fields[fieldi]; if ((*elements)[fieldi]) { error(loc, "duplicate initializer for field '%s'", vd->toChars()); errors = true; continue; } for (size_t j = 0; j < nfields; j++) { VarDeclaration *v2 = sd->fields[j]; bool overlap = (vd->offset < v2->offset + v2->type->size() && v2->offset < vd->offset + vd->type->size()); if (overlap && (*elements)[j]) { error(loc, "overlapping initialization for field %s and %s", v2->toChars(), vd->toChars()); errors = true; continue; } } assert(sc); Initializer *iz = value[i]; iz = iz->semantic(sc, vd->type->addMod(t->mod), needInterpret); Expression *ex = iz->toExpression(); if (ex->op == TOKerror) { errors = true; continue; } value[i] = iz; (*elements)[fieldi] = ex; ++fieldi; } if (errors) return new ErrorInitializer(); StructLiteralExp *sle = new StructLiteralExp(loc, sd, elements, t); if (!sd->fill(loc, elements, false)) return new ErrorInitializer(); sle->type = t; ExpInitializer *ie = new ExpInitializer(loc, sle); return ie->semantic(sc, t, needInterpret); } else if ((t->ty == Tdelegate || t->ty == Tpointer && t->nextOf()->ty == Tfunction) && value.dim == 0) { TOK tok = (t->ty == Tdelegate) ? TOKdelegate : TOKfunction; /* Rewrite as empty delegate literal { } */ Parameters *arguments = new Parameters; Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, tok, NULL); fd->fbody = new CompoundStatement(loc, new Statements()); fd->endloc = loc; Expression *e = new FuncExp(loc, fd); ExpInitializer *ie = new ExpInitializer(loc, e); return ie->semantic(sc, t, needInterpret); } error(loc, "a struct is not a valid initializer for a %s", t->toChars()); return new ErrorInitializer(); }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame && ident != Id::identifier && ident != Id::getProtection) { TemplateInstance::semanticTiargs(loc, sc, args, 1); } size_t dim = args ? args->dim : 0; Declaration *d; if (ident == Id::isArithmetic) { return isTypeX(&isTypeArithmetic); } else if (ident == Id::isFloating) { return isTypeX(&isTypeFloating); } else if (ident == Id::isIntegral) { return isTypeX(&isTypeIntegral); } else if (ident == Id::isScalar) { return isTypeX(&isTypeScalar); } else if (ident == Id::isUnsigned) { return isTypeX(&isTypeUnsigned); } else if (ident == Id::isAssociativeArray) { return isTypeX(&isTypeAssociativeArray); } else if (ident == Id::isStaticArray) { return isTypeX(&isTypeStaticArray); } else if (ident == Id::isAbstractClass) { return isTypeX(&isTypeAbstractClass); } else if (ident == Id::isFinalClass) { return isTypeX(&isTypeFinalClass); } else if (ident == Id::isPOD) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) { error("type expected as second argument of __traits %s instead of %s", ident->toChars(), o->toChars()); goto Lfalse; } if (t->toBasetype()->ty == Tstruct && ((sd = (StructDeclaration *)(((TypeStruct *)t->toBasetype())->sym)) != NULL)) { if (sd->isPOD()) goto Ltrue; else goto Lfalse; } goto Ltrue; } else if (ident == Id::isNested) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; if (!s) { } else if ((a = s->isAggregateDeclaration()) != NULL) { if (a->isNested()) goto Ltrue; else goto Lfalse; } else if ((f = s->isFuncDeclaration()) != NULL) { if (f->isNested()) goto Ltrue; else goto Lfalse; } error("aggregate or function expected instead of '%s'", o->toChars()); goto Lfalse; } else if (ident == Id::isAbstractFunction) { return isFuncX(&isFuncAbstractFunction); } else if (ident == Id::isVirtualFunction) { return isFuncX(&isFuncVirtualFunction); } else if (ident == Id::isVirtualMethod) { return isFuncX(&isFuncVirtualMethod); } else if (ident == Id::isFinalFunction) { return isFuncX(&isFuncFinalFunction); } else if (ident == Id::isStaticFunction) { return isFuncX(&isFuncStaticFunction); } else if (ident == Id::isRef) { return isDeclX(&isDeclRef); } else if (ident == Id::isOut) { return isDeclX(&isDeclOut); } else if (ident == Id::isLazy) { return isDeclX(&isDeclLazy); } else if (ident == Id::identifier) { // Get identifier for symbol as a string literal /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that * a symbol should not be folded to a constant. * Bit 1 means don't convert Parameter to Type if Parameter has an identifier */ TemplateInstance::semanticTiargs(loc, sc, args, 2); if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Parameter *po = isParameter(o); Identifier *id; if (po) { id = po->ident; assert(id); } else { Dsymbol *s = getDsymbol(o); if (!s || !s->ident) { error("argument %s has no identifier", o->toChars()); goto Lfalse; } id = s->ident; } StringExp *se = new StringExp(loc, id->toChars()); return se->semantic(sc); } else if (ident == Id::getProtection) { if (dim != 1) goto Ldimerror; Scope *sc2 = sc->push(); sc2->flags = sc->flags | SCOPEnoaccesscheck; TemplateInstance::semanticTiargs(loc, sc2, args, 1); sc2->pop(); RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { if (!isError(o)) error("argument %s has no protection", o->toChars()); goto Lfalse; } if (s->scope) s->semantic(s->scope); PROT protection = s->prot(); const char *protName = Pprotectionnames[protection]; assert(protName); StringExp *se = new StringExp(loc, (char *) protName); return se->semantic(sc); } else if (ident == Id::parent) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (s) { if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 s = fd->toAliasFunc(); if (!s->isImport()) // Bugzilla 8922 s = s->toParent(); } if (!s || s->isImport()) { error("argument %s has no parent", o->toChars()); goto Lfalse; } return (new DsymbolExp(loc, s))->semantic(sc); } else if (ident == Id::hasMember || ident == Id::getMember || ident == Id::getOverloads || ident == Id::getVirtualMethods || ident == Id::getVirtualFunctions) { if (dim != 2) goto Ldimerror; RootObject *o = (*args)[0]; Expression *e = isExpression((*args)[1]); if (!e) { error("expression expected as second argument of __traits %s", ident->toChars()); goto Lfalse; } e = e->ctfeInterpret(); StringExp *se = e->toString(); if (!se || se->length() == 0) { error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars()); goto Lfalse; } se = se->toUTF8(sc); if (se->sz != 1) { error("string must be chars"); goto Lfalse; } Identifier *id = Lexer::idPool((char *)se->string); /* Prefer dsymbol, because it might need some runtime contexts. */ Dsymbol *sym = getDsymbol(o); if (sym) { e = new DsymbolExp(loc, sym); e = new DotIdExp(loc, e, id); } else if (Type *t = isType(o)) e = typeDotIdExp(loc, t, id); else if (Expression *ex = isExpression(o)) e = new DotIdExp(loc, ex, id); else { error("invalid first argument"); goto Lfalse; } if (ident == Id::hasMember) { if (sym) { Dsymbol *sm = sym->search(loc, id, 0); if (sm) goto Ltrue; } /* Take any errors as meaning it wasn't found */ Scope *sc2 = sc->push(); e = e->trySemantic(sc2); sc2->pop(); if (!e) goto Lfalse; else goto Ltrue; } else if (ident == Id::getMember) { e = e->semantic(sc); return e; } else if (ident == Id::getVirtualFunctions || ident == Id::getVirtualMethods || ident == Id::getOverloads) { unsigned errors = global.errors; Expression *ex = e; e = e->semantic(sc); if (errors < global.errors) error("%s cannot be resolved", ex->toChars()); /* Create tuple of functions of e */ //e->dump(0); Expressions *exps = new Expressions(); FuncDeclaration *f; if (e->op == TOKvar) { VarExp *ve = (VarExp *)e; f = ve->var->isFuncDeclaration(); e = NULL; } else if (e->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)e; f = dve->var->isFuncDeclaration(); if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis) e = NULL; else e = dve->e1; } else f = NULL; Ptrait p; p.exps = exps; p.e1 = e; p.ident = ident; overloadApply(f, &p, &fptraits); TupleExp *tup = new TupleExp(loc, exps); return tup->semantic(sc); } else assert(0); } else if (ident == Id::classInstanceSize) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) { error("first argument is not a class"); goto Lfalse; } return new IntegerExp(loc, cd->structsize, Type::tsize_t); } else if (ident == Id::getAttributes) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { #if 0 Expression *e = isExpression(o); Type *t = isType(o); if (e) printf("e = %s %s\n", Token::toChars(e->op), e->toChars()); if (t) printf("t = %d %s\n", t->ty, t->toChars()); #endif error("first argument is not a symbol"); goto Lfalse; } //printf("getAttributes %s, %p\n", s->toChars(), s->userAttributes); if (!s->userAttributes) s->userAttributes = new Expressions(); TupleExp *tup = new TupleExp(loc, s->userAttributes); return tup->semantic(sc); } else if (ident == Id::allMembers || ident == Id::derivedMembers) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sd; if (!s) { error("argument has no members"); goto Lfalse; } Import *import; if ((import = s->isImport()) != NULL) { // Bugzilla 9692 sd = import->mod; } else if ((sd = s->isScopeDsymbol()) == NULL) { error("%s %s has no members", s->kind(), s->toChars()); goto Lfalse; } // use a struct as local function struct PushIdentsDg { static int dg(void *ctx, size_t n, Dsymbol *sm) { if (!sm) return 1; //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { if (sm->ident != Id::ctor && // backword compatibility sm->ident != Id::dtor && // backword compatibility sm->ident != Id::_postblit && // backword compatibility memcmp(sm->ident->string, "__", 2) == 0) { return 0; } //printf("\t%s\n", sm->ident->toChars()); Identifiers *idents = (Identifiers *)ctx; /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) { Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. assert(strcmp(id->toChars(), sm->ident->toChars()) != 0); #endif } idents->push(sm->ident); } else { EnumDeclaration *ed = sm->isEnumDeclaration(); if (ed) { ScopeDsymbol::foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx); } } return 0; } }; Identifiers *idents = new Identifiers; ScopeDsymbol::foreach(sc, sd->members, &PushIdentsDg::dg, idents); ClassDeclaration *cd = sd->isClassDeclaration(); if (cd && ident == Id::allMembers) { struct PushBaseMembers { static void dg(ClassDeclaration *cd, Identifiers *idents) { for (size_t i = 0; i < cd->baseclasses->dim; i++) { ClassDeclaration *cb = (*cd->baseclasses)[i]->base; ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents); if (cb->baseclasses->dim) dg(cb, idents); } } }; PushBaseMembers::dg(cd, idents); } // Turn Identifiers into StringExps reusing the allocated array assert(sizeof(Expressions) == sizeof(Identifiers)); Expressions *exps = (Expressions *)idents; for (size_t i = 0; i < idents->dim; i++) { Identifier *id = (*idents)[i]; StringExp *se = new StringExp(loc, id->toChars()); (*exps)[i] = se; } /* Making this a tuple is more flexible, as it can be statically unrolled. * To make an array literal, enclose __traits in [ ]: * [ __traits(allMembers, ...) ] */ Expression *e = new TupleExp(loc, exps); e = e->semantic(sc); return e; } else if (ident == Id::compiles) { /* Determine if all the objects - types, expressions, or symbols - * compile without error */ if (!dim) goto Lfalse; for (size_t i = 0; i < dim; i++) { unsigned errors = global.startGagging(); unsigned oldspec = global.speculativeGag; global.speculativeGag = global.gag; sc = sc->push(); sc->speculative = true; sc->flags = sc->enclosing->flags & ~SCOPEctfe; // inherit without CTFEing bool err = false; RootObject *o = (*args)[i]; Type *t = isType(o); Expression *e = t ? t->toExpression() : isExpression(o); if (!e && t) { Dsymbol *s; t->resolve(loc, sc, &e, &t, &s); if (t) { t->semantic(loc, sc); if (t->ty == Terror) err = true; } else if (s && s->errors) err = true; } if (e) { e = e->semantic(sc); e = e->optimize(WANTvalue); if (e->op == TOKerror) err = true; } sc = sc->pop(); global.speculativeGag = oldspec; if (global.endGagging(errors) || err) { goto Lfalse; } } goto Ltrue; } else if (ident == Id::isSame) { /* Determine if two symbols are the same */ if (dim != 2) goto Ldimerror; TemplateInstance::semanticTiargs(loc, sc, args, 0); RootObject *o1 = (*args)[0]; RootObject *o2 = (*args)[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); #if 0 printf("o1: %p\n", o1); printf("o2: %p\n", o2); if (!s1) { Expression *ea = isExpression(o1); if (ea) printf("%s\n", ea->toChars()); Type *ta = isType(o1); if (ta) printf("%s\n", ta->toChars()); goto Lfalse; } else printf("%s %s\n", s1->kind(), s1->toChars()); #endif if (!s1 && !s2) { Expression *ea1 = isExpression(o1); Expression *ea2 = isExpression(o2); if (ea1 && ea2) { if (ea1->equals(ea2)) goto Ltrue; } } if (!s1 || !s2) goto Lfalse; s1 = s1->toAlias(); s2 = s2->toAlias(); if (s1->isFuncAliasDeclaration()) s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc(); if (s2->isFuncAliasDeclaration()) s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc(); if (s1 == s2) goto Ltrue; else goto Lfalse; } else if (ident == Id::getUnitTests) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (!s) { error("argument %s to __traits(getUnitTests) must be a module or aggregate", o->toChars()); goto Lfalse; } Import *imp = s->isImport(); if (imp) // Bugzilla 10990 s = imp->mod; ScopeDsymbol* scope = s->isScopeDsymbol(); if (!scope) { error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", s->toChars(), s->kind()); goto Lfalse; } Expressions* unitTests = new Expressions(); Dsymbols* symbols = scope->members; if (global.params.useUnitTests && symbols) { // Should actually be a set AA* uniqueUnitTests = NULL; collectUnitTests(symbols, uniqueUnitTests, unitTests); } TupleExp *tup = new TupleExp(loc, unitTests); return tup->semantic(sc); } else if (ident == Id::isOverrideFunction) { return isFuncX(&isFuncOverrideFunction); } else if(ident == Id::getVirtualIndex) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); FuncDeclaration *fd; if (!s || (fd = s->isFuncDeclaration()) == NULL) { error("first argument to __traits(getVirtualIndex) must be a function"); goto Lfalse; } fd = fd->toAliasFunc(); // Neccessary to support multiple overloads. ptrdiff_t result = fd->isVirtual() ? fd->vtblIndex : -1; return new IntegerExp(loc, fd->vtblIndex, Type::tptrdiff_t); } else { error("unrecognized trait %s", ident->toChars()); goto Lfalse; } return NULL; Ldimerror: error("wrong number of arguments %d", (int)dim); goto Lfalse; Lfalse: return new IntegerExp(loc, 0, Type::tbool); Ltrue: return new IntegerExp(loc, 1, Type::tbool); }
/*************************************** * This works by transforming a struct initializer into * a struct literal. In the future, the two should be the * same thing. */ Expression *StructInitializer::toExpression() { Expression *e; size_t offset; //printf("StructInitializer::toExpression() %s\n", toChars()); if (!ad) // if fwd referenced { return NULL; } StructDeclaration *sd = ad->isStructDeclaration(); if (!sd) return NULL; Expressions *elements = new Expressions(); size_t nfields = ad->fields.dim; #if DMDV2 if (sd->isnested) nfields--; #endif elements->setDim(nfields); for (size_t i = 0; i < elements->dim; i++) { elements->tdata()[i] = NULL; } unsigned fieldi = 0; for (size_t i = 0; i < value.dim; i++) { Identifier *id = field.tdata()[i]; if (id) { Dsymbol * s = ad->search(loc, id, 0); if (!s) { error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); goto Lno; } // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { s->error("is not a per-instance initializable field"); goto Lno; } if (s == ad->fields.tdata()[fieldi]) break; } } else if (fieldi >= nfields) { error(loc, "too many initializers for '%s'", ad->toChars()); goto Lno; } Initializer *iz = value.tdata()[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) goto Lno; if (elements->tdata()[fieldi]) { error(loc, "duplicate initializer for field '%s'", ad->fields.tdata()[fieldi]->toChars()); goto Lno; } elements->tdata()[fieldi] = ex; ++fieldi; } // Now, fill in any missing elements with default initializers. // We also need to validate any anonymous unions offset = 0; for (size_t i = 0; i < elements->dim; ) { VarDeclaration * vd = ad->fields.tdata()[i]->isVarDeclaration(); //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset); if (vd->offset < offset) { // Only the first field of a union can have an initializer if (elements->tdata()[i]) goto Lno; } else { if (!elements->tdata()[i]) // Default initialize elements->tdata()[i] = vd->type->defaultInit(); } offset = vd->offset + vd->type->size(); i++; #if 0 int unionSize = ad->numFieldsInUnion(i); if (unionSize == 1) { // Not a union -- default initialize if missing if (!elements->tdata()[i]) elements->tdata()[i] = vd->type->defaultInit(); } else { // anonymous union -- check for errors int found = -1; // index of the first field with an initializer for (int j = i; j < i + unionSize; ++j) { if (!elements->tdata()[j]) continue; if (found >= 0) { VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); error(loc, "%s cannot have initializers for fields %s and %s in same union", ad->toChars(), v1->toChars(), v->toChars()); goto Lno; } found = j; } if (found == -1) { error(loc, "no initializer for union that contains field %s", vd->toChars()); goto Lno; } } i += unionSize; #endif } e = new StructLiteralExp(loc, sd, elements); e->type = sd->type; return e; Lno: delete elements; return NULL; }
void AggregateDeclaration::semantic3(Scope *sc) { //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors); if (!members) return; StructDeclaration *sd = isStructDeclaration(); if (!sc) // from runDeferredSemantic3 for TypeInfo generation { assert(sd); sd->semanticTypeInfoMembers(); return; } Scope *sc2 = sc->push(this); sc2->stc &= STCsafe | STCtrusted | STCsystem; sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttribDecl = NULL; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->semantic3(sc2); } sc2->pop(); // don't do it for unused deprecated types // or error types if (!getRTInfo && Type::rtinfo && (!isDeprecated() || global.params.useDeprecated) && (type && type->ty != Terror)) { // we do not want to report deprecated uses of this type during RTInfo // generation, so we disable reporting deprecation temporarily // WARNING: Muting messages during analysis of RTInfo might silently instantiate // templates that use (other) deprecated types. If these template instances // are used in other parts of the program later, they will be reused without // ever producing the deprecation message. The implementation here restricts // muting to the types that RTInfo is currently generated for. bool wasmuted = mutedeprecation; mutedeprecation = true; // Evaluate: RTinfo!type Objects *tiargs = new Objects(); tiargs->push(type); TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs); ti->semantic(sc); ti->semantic2(sc); ti->semantic3(sc); Dsymbol *s = ti->toAlias(); Expression *e = new DsymbolExp(Loc(), s, 0); Scope *sc3 = ti->tempdecl->scope->startCTFE(); sc3->tinst = sc->tinst; e = e->semantic(sc3); sc3->endCTFE(); e = e->ctfeInterpret(); getRTInfo = e; mutedeprecation = wasmuted; } if (sd) sd->semanticTypeInfoMembers(); }
void TypeInfoStructDeclaration::llvmDefine() { Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); LOG_SCOPE; // make sure struct is resolved assert(tinfo->ty == Tstruct); TypeStruct *tc = static_cast<TypeStruct *>(tinfo); StructDeclaration *sd = tc->sym; // can't emit typeinfo for forward declarations if (sd->sizeok != 1) { sd->error("cannot emit TypeInfo for forward declaration"); fatal(); } sd->codegen(Type::sir); IrStruct* irstruct = sd->ir.irStruct; RTTIBuilder b(Type::typeinfostruct); // char[] name b.push_string(sd->toPrettyChars()); // void[] init // never emit a null array, even for zero initialized typeinfo // the size() method uses this array! size_t init_size = getTypeStoreSize(tc->irtype->getType()); b.push_void_array(init_size, irstruct->getInitSymbol()); // toX functions ground work static TypeFunction *tftohash; static TypeFunction *tftostring; if (!tftohash) { Scope sc; tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); #if DMDV2 tftohash ->mod = MODconst; #endif tftohash = static_cast<TypeFunction *>(tftohash->semantic(0, &sc)); #if DMDV2 Type *retType = Type::tchar->invariantOf()->arrayOf(); #else Type *retType = Type::tchar->arrayOf(); #endif tftostring = new TypeFunction(NULL, retType, 0, LINKd); tftostring = static_cast<TypeFunction *>(tftostring->semantic(0, &sc)); } // this one takes a parameter, so we need to build a new one each time // to get the right type. can we avoid this? TypeFunction *tfcmpptr; { Scope sc; Parameters *arguments = new Parameters; #if STRUCTTHISREF // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); #else // arg type is const T* Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); #endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); #if DMDV2 tfcmpptr->mod = MODconst; #endif tfcmpptr = static_cast<TypeFunction *>(tfcmpptr->semantic(0, &sc)); } // well use this module for all overload lookups Module *gm = getModule(); // toHash FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm); b.push_funcptr(fd); // opEquals #if DMDV2 fd = sd->xeq; #else fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); #endif b.push_funcptr(fd); // opCmp fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm); b.push_funcptr(fd); // toString fd = find_method_overload(sd, Id::tostring, tftostring, gm); b.push_funcptr(fd); // uint m_flags; unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); #if DMDV2 ClassDeclaration* tscd = Type::typeinfostruct; assert((!global.params.is64bit && tscd->fields.dim == 11) || (global.params.is64bit && tscd->fields.dim == 13)); //void function(void*) xdtor; b.push_funcptr(sd->dtor); //void function(void*) xpostblit; FuncDeclaration *xpostblit = sd->postblit; if (xpostblit && sd->postblit->storage_class & STCdisable) xpostblit = 0; b.push_funcptr(xpostblit); //uint m_align; b.push_uint(tc->alignsize()); if (global.params.is64bit) { // TypeInfo m_arg1; // TypeInfo m_arg2; TypeTuple *tup = tc->toArgTypes(); assert(tup->arguments->dim <= 2); for (unsigned i = 0; i < 2; i++) { if (i < tup->arguments->dim) { Type *targ = static_cast<Parameter *>(tup->arguments->data[i])->type; targ = targ->merge(); b.push_typeinfo(targ); } else b.push_null(Type::typeinfo->type); } } // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (sd->getRTInfo) b.push(sd->getRTInfo->toConstElem(gIR)); else if (!tc->hasPointers()) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers #endif // finish b.finalize(ir.irGlobal); }
void TypeInfoStructDeclaration::toDt(dt_t **pdt) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); unsigned offset = Type::typeinfostruct->structsize; dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct dtdword(pdt, 0); // monitor assert(tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)tinfo; StructDeclaration *sd = tc->sym; /* Put out: * char[] name; * void[] init; * hash_t function(void*) xtoHash; * int function(void*,void*) xopEquals; * int function(void*,void*) xopCmp; * char[] function(void*) xtoString; * uint m_flags; * * name[] */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtdword(pdt, namelen); //dtabytes(pdt, TYnptr, 0, namelen + 1, name); dtxoff(pdt, toSymbol(), offset, TYnptr); offset += namelen + 1; // void[] init; dtdword(pdt, sd->structsize); // init.length if (sd->zeroInit) dtdword(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0, TYnptr); // init.ptr FuncDeclaration *fd; FuncDeclaration *fdx; TypeFunction *tf; Type *ta; Dsymbol *s; static TypeFunction *tftohash; static TypeFunction *tftostring; if (!tftohash) { Scope sc; tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); tftohash = (TypeFunction *)tftohash->semantic(0, &sc); tftostring = new TypeFunction(NULL, Type::tchar->arrayOf(), 0, LINKd); tftostring = (TypeFunction *)tftostring->semantic(0, &sc); } TypeFunction *tfeqptr; { Scope sc; Parameters *arguments = new Parameters; #if STRUCTTHISREF // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); #else // arg type is const T* Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); #endif arguments->push(arg); tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeqptr = (TypeFunction *)tfeqptr->semantic(0, &sc); } #if 0 TypeFunction *tfeq; { Scope sc; Array *arguments = new Array; Parameter *arg = new Parameter(In, tc, NULL, NULL); arguments->push(arg); tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeq = (TypeFunction *)tfeq->semantic(0, &sc); } #endif s = search_function(sd, Id::tohash); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftohash); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) uint toHash()"); dtdword(pdt, 0); } else dtdword(pdt, 0); s = search_function(sd, Id::eq); fdx = s ? s->isFuncDeclaration() : NULL; for (int i = 0; i < 2; i++) { if (fdx) { fd = fdx->overloadExactMatch(tfeqptr); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtdword(pdt, 0); } else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtdword(pdt, 0); s = search_function(sd, Id::cmp); fdx = s ? s->isFuncDeclaration() : NULL; } s = search_function(sd, Id::tostring); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftostring); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) char[] toString()"); dtdword(pdt, 0); } else dtdword(pdt, 0); // uint m_flags; dtdword(pdt, tc->hasPointers()); #if DMDV2 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr); else dtdword(pdt, 0); // xgetMembers // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr); else dtdword(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit) dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr); else dtdword(pdt, 0); // xpostblit #endif // name[] dtnbytes(pdt, namelen + 1, name); }
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) { if (FuncDeclaration *f = hasIdentityOpAssign(sc)) { hasIdentityAssign = 1; return f; } // Even if non-identity opAssign is defined, built-in identity opAssign // will be defined. if (!needOpAssign()) return NULL; //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); StorageClass stc = STCsafe | STCnothrow | STCpure; Loc declLoc = this->loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage if (dtor || postblit) { if (dtor) stc = mergeFuncAttrs(stc, dtor->storage_class); } else { for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->isField()); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; tv = tv->nextOf()->toBasetype(); } if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (FuncDeclaration *f = sd->hasIdentityOpAssign(sc)) stc = mergeFuncAttrs(stc, f->storage_class); } } } Parameters *fparams = new Parameters; fparams->push(new Parameter(STCnodtor, type, Id::p, NULL)); Type *tf = new TypeFunction(fparams, handle, 0, LINKd, stc | STCref); FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf); Expression *e = NULL; if (stc & STCdisable) { } else if (dtor || postblit) { /* Do swap this and rhs * tmp = this; this = s; tmp.dtor(); */ //printf("\tswap copy\n"); Identifier *idtmp = Lexer::uniqueId("__tmp"); VarDeclaration *tmp; AssignExp *ec = NULL; if (dtor) { tmp = new VarDeclaration(loc, type, idtmp, new VoidInitializer(loc)); tmp->noscope = 1; tmp->storage_class |= STCctfe; e = new DeclarationExp(loc, tmp); ec = new AssignExp(loc, new VarExp(loc, tmp), new ThisExp(loc) ); ec->op = TOKblit; e = Expression::combine(e, ec); } ec = new AssignExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id::p)); ec->op = TOKblit; e = Expression::combine(e, ec); if (dtor) { /* Instead of running the destructor on s, run it * on tmp. This avoids needing to copy tmp back in to s. */ Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), dtor, 0); ec2 = new CallExp(loc, ec2); e = Expression::combine(e, ec2); } } else { /* Do memberwise copy */ //printf("\tmemberwise copy\n"); for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->isField()); // this.v = s.v; AssignExp *ec = new AssignExp(loc, new DotVarExp(loc, new ThisExp(loc), v, 0), new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0)); e = Expression::combine(e, ec); } } if (e) { Statement *s1 = new ExpStatement(loc, e); /* Add: * return this; */ e = new ThisExp(loc); Statement *s2 = new ReturnStatement(loc, e); fop->fbody = new CompoundStatement(loc, s1, s2); } Dsymbol *s = fop; #if 1 // workaround until fixing issue 1528 Dsymbol *assign = search_function(this, Id::assign); if (assign && assign->isTemplateDeclaration()) { // Wrap a template around the function declaration TemplateParameters *tpl = new TemplateParameters(); Dsymbols *decldefs = new Dsymbols(); decldefs->push(s); TemplateDeclaration *tempdecl = new TemplateDeclaration(assign->loc, fop->ident, tpl, NULL, decldefs, 0); s = tempdecl; } #endif members->push(s); s->addMember(sc, this, 1); this->hasIdentityAssign = 1; // temporary mark identity assignable unsigned errors = global.startGagging(); // Do not report errors, even if the unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. global.speculativeGag = global.gag; Scope *sc2 = sc->push(); sc2->stc = 0; sc2->linkage = LINKd; sc2->speculative = true; s->semantic(sc2); s->semantic2(sc2); s->semantic3(sc2); sc2->pop(); global.speculativeGag = oldspec; if (global.endGagging(errors)) // if errors happened { // Disable generated opAssign, because some members forbid identity assignment. fop->storage_class |= STCdisable; fop->fbody = NULL; // remove fbody which contains the error } //printf("-StructDeclaration::buildOpAssign() %s %s, errors = %d\n", toChars(), s->kind(), (fop->storage_class & STCdisable) != 0); return fop; }
void visit(TypeInfoStructDeclaration *d) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); if (global.params.is64bit) verifyStructSize(Type::typeinfostruct, 17 * Target::ptrsize); else verifyStructSize(Type::typeinfostruct, 15 * Target::ptrsize); dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0); // vtbl for TypeInfo_Struct dtsize_t(pdt, 0); // monitor assert(d->tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)d->tinfo; StructDeclaration *sd = tc->sym; if (!sd->members) return; /* Put out: * char[] name; * void[] init; * hash_t function(in void*) xtoHash; * bool function(in void*, in void*) xopEquals; * int function(in void*, in void*) xopCmp; * string function(const(void)*) xtoString; * StructFlags m_flags; * //xgetMembers; * xdtor; * xpostblit; * uint m_align; * version (X86_64) * TypeInfo m_arg1; * TypeInfo m_arg2; * xgetRTInfo */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtsize_t(pdt, namelen); dtabytes(pdt, 0, namelen + 1, name); // void[] init; dtsize_t(pdt, sd->structsize); // init.length if (sd->zeroInit) dtsize_t(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0); // init.ptr if (FuncDeclaration *fd = search_toHash(sd)) { dtxoff(pdt, fd->toSymbol(), 0); TypeFunction *tf = (TypeFunction *)fd->type; assert(tf->ty == Tfunction); /* I'm a little unsure this is the right way to do it. Perhaps a better * way would to automatically add these attributes to any struct member * function with the name "toHash". * So I'm leaving this here as an experiment for the moment. */ if (!tf->isnothrow || tf->trust == TRUSTsystem /*|| tf->purity == PUREimpure*/) warning(fd->loc, "toHash() must be declared as extern (D) size_t toHash() const nothrow @safe, not %s", tf->toChars()); } else dtsize_t(pdt, 0); if (sd->xeq) dtxoff(pdt, sd->xeq->toSymbol(), 0); else dtsize_t(pdt, 0); if (sd->xcmp) dtxoff(pdt, sd->xcmp->toSymbol(), 0); else dtsize_t(pdt, 0); if (FuncDeclaration *fd = search_toString(sd)) { dtxoff(pdt, fd->toSymbol(), 0); } else dtsize_t(pdt, 0); // StructFlags m_flags; StructFlags::Type m_flags = 0; if (tc->hasPointers()) m_flags |= StructFlags::hasPointers; dtsize_t(pdt, m_flags); #if 0 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0); else dtsize_t(pdt, 0); // xgetMembers #endif // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0); else dtsize_t(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit && !(spostblit->storage_class & STCdisable)) dtxoff(pdt, spostblit->toSymbol(), 0); else dtsize_t(pdt, 0); // xpostblit // uint m_align; dtsize_t(pdt, tc->alignsize()); if (global.params.is64bit) { Type *t = sd->arg1type; for (int i = 0; i < 2; i++) { // m_argi if (t) { t->genTypeInfo(NULL); dtxoff(pdt, t->vtinfo->toSymbol(), 0); } else dtsize_t(pdt, 0); t = sd->arg2type; } } // xgetRTInfo if (sd->getRTInfo) sd->getRTInfo->toDt(pdt); else if (m_flags & StructFlags::hasPointers) dtsize_t(pdt, 1); else dtsize_t(pdt, 0); }
void visit(TypeInfoStructDeclaration *decl) override { IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; // make sure struct is resolved assert(decl->tinfo->ty == Tstruct); TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo); StructDeclaration *sd = tc->sym; // handle opaque structs if (!sd->members) { RTTIBuilder b(Type::typeinfostruct); b.finalize(getIrGlobal(decl)); return; } // can't emit typeinfo for forward declarations if (sd->sizeok != SIZEOKdone) { sd->error("cannot emit TypeInfo for forward declaration"); fatal(); } DtoResolveStruct(sd); if (TemplateInstance *ti = sd->isInstantiated()) { if (!ti->needsCodegen()) { assert(ti->minst || sd->requestTypeInfo); // We won't emit ti, so emit the special member functions in here. if (sd->xeq && sd->xeq != StructDeclaration::xerreq) { Declaration_codegen(sd->xeq); } if (sd->xcmp && sd->xcmp != StructDeclaration::xerrcmp) { Declaration_codegen(sd->xcmp); } if (FuncDeclaration *ftostr = search_toString(sd)) { Declaration_codegen(ftostr); } if (sd->xhash) { Declaration_codegen(sd->xhash); } if (sd->postblit) { Declaration_codegen(sd->postblit); } if (sd->dtor) { Declaration_codegen(sd->dtor); } } } IrAggr *iraggr = getIrAggr(sd); RTTIBuilder b(Type::typeinfostruct); // On x86_64, class TypeInfo_Struct contains 2 additional fields // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs // implementation. They are not present on any other cpu/os. unsigned expectedFields = 12; if (global.params.targetTriple->getArch() == llvm::Triple::x86_64) { expectedFields += 2; } if (Type::typeinfostruct->fields.dim != expectedFields) { error(Loc(), "Unexpected number of object.TypeInfo_Struct fields; " "druntime version does not match compiler"); fatal(); } // char[] name b.push_string(sd->toPrettyChars()); // void[] init // The protocol is to write a null pointer for zero-initialized arrays. The // length field is always needed for tsize(). llvm::Constant *initPtr; if (tc->isZeroInit(Loc())) { initPtr = getNullValue(getVoidPtrType()); } else { initPtr = iraggr->getInitSymbol(); } b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr); // toHash FuncDeclaration *fd = sd->xhash; b.push_funcptr(fd); // opEquals fd = sd->xeq; b.push_funcptr(fd); // opCmp fd = sd->xcmp; b.push_funcptr(fd); // toString fd = search_toString(sd); b.push_funcptr(fd); // uint m_flags; unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); // void function(void*) xdtor; b.push_funcptr(sd->dtor); // void function(void*) xpostblit; FuncDeclaration *xpostblit = sd->postblit; if (xpostblit && sd->postblit->storage_class & STCdisable) { xpostblit = nullptr; } b.push_funcptr(xpostblit); // uint m_align; b.push_uint(DtoAlignment(tc)); if (global.params.is64bit) { // TypeInfo m_arg1; // TypeInfo m_arg2; Type *t = sd->arg1type; for (unsigned i = 0; i < 2; i++) { if (t) { t = t->merge(); b.push_typeinfo(t); } else { b.push_null(Type::dtypeinfo->type); } t = sd->arg2type; } } // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (sd->getRTInfo) { b.push(toConstElem(sd->getRTInfo, gIR)); } else if (!tc->hasPointers()) { b.push_size_as_vp(0); // no pointers } else { b.push_size_as_vp(1); // has pointers } // finish b.finalize(getIrGlobal(decl)); }
void visit(TypeInfoStructDeclaration *decl) { IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", decl->toChars()); LOG_SCOPE; // make sure struct is resolved assert(decl->tinfo->ty == Tstruct); TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo); StructDeclaration *sd = tc->sym; // handle opaque structs if (!sd->members) { RTTIBuilder b(Type::typeinfostruct); b.finalize(getIrGlobal(decl)); return; } // can't emit typeinfo for forward declarations if (sd->sizeok != SIZEOKdone) { sd->error("cannot emit TypeInfo for forward declaration"); fatal(); } DtoResolveStruct(sd); IrAggr* iraggr = getIrAggr(sd); RTTIBuilder b(Type::typeinfostruct); // char[] name b.push_string(sd->toPrettyChars()); // void[] init // The protocol is to write a null pointer for zero-initialized arrays. The // length field is always needed for tsize(). llvm::Constant *initPtr; if (tc->isZeroInit(Loc())) initPtr = getNullValue(getVoidPtrType()); else initPtr = iraggr->getInitSymbol(); b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr); // well use this module for all overload lookups // toHash FuncDeclaration* fd = sd->xhash; b.push_funcptr(fd); // opEquals fd = sd->xeq; b.push_funcptr(fd); // opCmp fd = sd->xcmp; b.push_funcptr(fd); // toString fd = search_toString(sd); b.push_funcptr(fd); // uint m_flags; unsigned hasptrs = tc->hasPointers() ? 1 : 0; b.push_uint(hasptrs); // On x86_64, class TypeInfo_Struct contains 2 additional fields // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs // implementation. They are not present on any other cpu/os. assert((global.params.targetTriple.getArch() != llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 11) || (global.params.targetTriple.getArch() == llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 13)); //void function(void*) xdtor; b.push_funcptr(sd->dtor); //void function(void*) xpostblit; FuncDeclaration *xpostblit = sd->postblit; if (xpostblit && sd->postblit->storage_class & STCdisable) xpostblit = 0; b.push_funcptr(xpostblit); //uint m_align; b.push_uint(tc->alignsize()); if (global.params.is64bit) { // TypeInfo m_arg1; // TypeInfo m_arg2; Type *t = sd->arg1type; for (unsigned i = 0; i < 2; i++) { if (t) { t = t->merge(); b.push_typeinfo(t); } else b.push_null(Type::dtypeinfo->type); t = sd->arg2type; } } // immutable(void)* m_RTInfo; // The cases where getRTInfo is null are not quite here, but the code is // modelled after what DMD does. if (sd->getRTInfo) b.push(toConstElem(sd->getRTInfo, gIR)); else if (!tc->hasPointers()) b.push_size_as_vp(0); // no pointers else b.push_size_as_vp(1); // has pointers // finish b.finalize(getIrGlobal(decl)); }
Expression *StructInitializer::fill(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("StructInitializer::fill(sc = %p, '%s')\n", sc, toChars()); assert(t->ty == Tstruct); StructDeclaration *sd = ((TypeStruct *)t)->sym; sd->size(loc); if (sd->sizeok != SIZEOKdone) return new ErrorExp(); size_t nfields = sd->fields.dim - sd->isNested(); Expressions *elements = new Expressions(); elements->setDim(nfields); for (size_t i = 0; i < elements->dim; i++) (*elements)[i] = NULL; // Run semantic for explicitly given initializers bool errors = false; for (size_t fieldi = 0, i = 0; i < field.dim; i++) { if (Identifier *id = field[i]) { Dsymbol *s = sd->search(loc, id, 0); if (!s) { s = sd->search_correct(id); if (s) error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", id->toChars(), sd->toChars(), s->kind(), s->toChars()); else error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); return new ErrorExp(); } s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { error(loc, "%s.%s is not a per-instance initializable field", sd->toChars(), s->toChars()); return new ErrorExp(); } if (s == sd->fields[fieldi]) break; } } else if (fieldi >= nfields) { error(loc, "too many initializers for %s", sd->toChars()); return new ErrorExp(); } VarDeclaration *vd = sd->fields[fieldi]; if ((*elements)[fieldi]) { error(loc, "duplicate initializer for field '%s'", vd->toChars()); errors = true; continue; } for (size_t j = 0; j < nfields; j++) { VarDeclaration *v2 = sd->fields[j]; bool overlap = (vd->offset < v2->offset + v2->type->size() && v2->offset < vd->offset + vd->type->size()); if (overlap && (*elements)[j]) { error(loc, "overlapping initialization for field %s and %s", v2->toChars(), vd->toChars()); errors = true; continue; } } assert(sc); Initializer *iz = value[i]; iz = iz->semantic(sc, vd->type->addMod(t->mod), needInterpret); Expression *ex = iz->toExpression(); if (ex->op == TOKerror) { errors = true; continue; } value[i] = iz; (*elements)[fieldi] = ex; ++fieldi; } if (errors) return new ErrorExp(); // Fill in missing any elements with default initializers for (size_t i = 0; i < elements->dim; i++) { if ((*elements)[i]) continue; VarDeclaration *vd = sd->fields[i]; VarDeclaration *vx = vd; if (vd->init && vd->init->isVoidInitializer()) vx = NULL; // Find overlapped fields with the hole [vd->offset .. vd->offset->size()]. size_t fieldi = i; for (size_t j = 0; j < nfields; j++) { if (i == j) continue; VarDeclaration *v2 = sd->fields[j]; if (v2->init && v2->init->isVoidInitializer()) continue; bool overlap = (vd->offset < v2->offset + v2->type->size() && v2->offset < vd->offset + vd->type->size()); if (!overlap) continue; if ((*elements)[j]) { vx = NULL; break; } #if 1 /* Prefer first found non-void-initialized field * union U { int a; int b = 2; } * U u; // Error: overlapping initialization for field a and b */ if (!vx) vx = v2, fieldi = j; else if (v2->init) { error(loc, "overlapping initialization for field %s and %s", v2->toChars(), vd->toChars()); } #else // fix Bugzilla 1432 /* Prefer explicitly initialized field * union U { int a; int b = 2; } * U u; // OK (u.b == 2) */ if (!vx || !vx->init && v2->init) vx = v2, fieldi = j; else if (vx->init && v2->init) { error(loc, "overlapping default initialization for field %s and %s", v2->toChars(), vd->toChars()); } else assert(vx->init || !vx->init && !v2->init); #endif } if (vx) { if (vx->init) { assert(!vx->init->isVoidInitializer()); if (vx->scope) { // Do deferred semantic analysis Initializer *i2 = vx->init->syntaxCopy(); i2 = i2->semantic(vx->scope, vx->type, INITinterpret); (*elements)[fieldi] = i2->toExpression(); if (!global.gag) { vx->scope = NULL; vx->init = i2; // save result } } else (*elements)[fieldi] = vx->init->toExpression(); } else (*elements)[fieldi] = vx->type->defaultInit(); } } for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (e && e->op == TOKerror) return e; } Expression *e = new StructLiteralExp(loc, sd, elements, t); if (sc) e = e->semantic(sc); else e->type = sd->type; // from glue layer return e; }
Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { int errors = 0; //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); vars.setDim(field.dim); t = t->toBasetype(); if (t->ty == Tstruct) { unsigned fieldi = 0; TypeStruct *ts = (TypeStruct *)t; ad = ts->sym; if (ad->ctor) error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", ad->kind(), ad->toChars(), ad->toChars()); StructDeclaration *sd = ad->isStructDeclaration(); assert(sd); sd->size(loc); if (sd->sizeok != SIZEOKdone) { error(loc, "struct %s is forward referenced", sd->toChars()); errors = 1; goto Lerror; } size_t nfields = sd->fields.dim; if (sd->isnested) nfields--; for (size_t i = 0; i < field.dim; i++) { Identifier *id = field[i]; Initializer *val = value[i]; Dsymbol *s; VarDeclaration *v; if (id == NULL) { if (fieldi >= nfields) { error(loc, "too many initializers for %s", ad->toChars()); errors = 1; field.remove(i); i--; continue; } else { s = ad->fields[fieldi]; } } else { //s = ad->symtab->lookup(id); s = ad->search(loc, id, 0); if (!s) { s = ad->search_correct(id); if (s) error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", id->toChars(), t->toChars(), s->kind(), s->toChars()); else error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); errors = 1; continue; } s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { error(loc, "%s.%s is not a per-instance initializable field", t->toChars(), s->toChars()); errors = 1; break; } if (s == ad->fields[fieldi]) break; } } if (s && (v = s->isVarDeclaration()) != NULL) { val = val->semantic(sc, v->type->addMod(t->mod), needInterpret); value[i] = val; vars[i] = v; } else { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); errors = 1; } fieldi++; } } else if (t->ty == Tdelegate && value.dim == 0) { /* Rewrite as empty delegate literal { } */ Parameters *arguments = new Parameters; Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL); fd->fbody = new CompoundStatement(loc, new Statements()); fd->endloc = loc; Expression *e = new FuncExp(loc, fd); ExpInitializer *ie = new ExpInitializer(loc, e); return ie->semantic(sc, t, needInterpret); } else { error(loc, "a struct is not a valid initializer for a %s", t->toChars()); errors = 1; } Lerror: if (errors) { field.setDim(0); value.setDim(0); vars.setDim(0); } return this; }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame && ident != Id::identifier) { TemplateInstance::semanticTiargs(loc, sc, args, 1); } size_t dim = args ? args->dim : 0; Declaration *d; #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ { Type *t = getType((*args)[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ { Dsymbol *s = getDsymbol((*args)[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ goto Lfalse; \ } \ if (!dim) \ goto Lfalse; \ goto Ltrue; if (ident == Id::isArithmetic) { ISTYPE(t->isintegral() || t->isfloating()) } else if (ident == Id::isFloating) { ISTYPE(t->isfloating()) } else if (ident == Id::isIntegral) { ISTYPE(t->isintegral()) } else if (ident == Id::isScalar) { ISTYPE(t->isscalar()) } else if (ident == Id::isUnsigned) { ISTYPE(t->isunsigned()) } else if (ident == Id::isAssociativeArray) { ISTYPE(t->toBasetype()->ty == Taarray) } else if (ident == Id::isStaticArray) { ISTYPE(t->toBasetype()->ty == Tsarray) } else if (ident == Id::isAbstractClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract()) } else if (ident == Id::isFinalClass) { ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) } else if (ident == Id::isPOD) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Type *t = isType(o); StructDeclaration *sd; if (!t) { error("type expected as second argument of __traits %s instead of %s", ident->toChars(), o->toChars()); goto Lfalse; } if (t->toBasetype()->ty == Tstruct && ((sd = (StructDeclaration *)(((TypeStruct *)t->toBasetype())->sym)) != NULL)) { if (sd->isPOD()) goto Ltrue; else goto Lfalse; } goto Ltrue; } else if (ident == Id::isNested) { if (dim != 1) goto Ldimerror; RootObject *o = (*args)[0]; Dsymbol *s = getDsymbol(o); AggregateDeclaration *a; FuncDeclaration *f; if (!s) { } else if ((a = s->isAggregateDeclaration()) != NULL) { if (a->isNested()) goto Ltrue; else goto Lfalse; } else if ((f = s->isFuncDeclaration()) != NULL) { if (f->isNested()) goto Ltrue; else goto Lfalse; } error("aggregate or function expected instead of '%s'", o->toChars()); goto Lfalse; } else if (ident == Id::isAbstractFunction) { FuncDeclaration *f; ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) }
void visit(TypeStruct *t) { //printf("TypeStruct::toCtype() '%s'\n", t->sym->toChars()); Type *tm = t->mutableOf(); if (tm->ctype) { t->ctype = type_alloc(tybasic(tm->ctype->Tty)); t->ctype->Tcount++; if (t->ctype->Tty == TYstruct) { Symbol *s = tm->ctype->Ttag; t->ctype->Ttag = (Classsym *)s; // structure tag name } // Add modifiers switch (t->mod) { case 0: assert(0); break; case MODconst: case MODwild: case MODwildconst: t->ctype->Tty |= mTYconst; break; case MODshared: t->ctype->Tty |= mTYshared; break; case MODshared | MODconst: case MODshared | MODwild: case MODshared | MODwildconst: t->ctype->Tty |= mTYshared | mTYconst; break; case MODimmutable: t->ctype->Tty |= mTYimmutable; break; default: assert(0); } } else { StructDeclaration *sym = t->sym; if (sym->ident == Id::__c_long_double) { t->ctype = type_fake(TYdouble); t->ctype->Tcount++; return; } t->ctype = type_struct_class(sym->toPrettyChars(true), sym->alignsize, sym->structsize, sym->arg1type ? Type_toCtype(sym->arg1type) : NULL, sym->arg2type ? Type_toCtype(sym->arg2type) : NULL, sym->isUnionDeclaration() != 0, false, sym->isPOD() != 0); tm->ctype = t->ctype; /* Add in fields of the struct * (after setting ctype to avoid infinite recursion) */ if (global.params.symdebug) { for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = sym->fields[i]; symbol_struct_addField(t->ctype->Ttag, v->ident->toChars(), Type_toCtype(v->type), v->offset); } } } //printf("t = %p, Tflags = x%x\n", ctype, ctype->Tflags); }
void TypeInfoStructDeclaration::toDt(dt_t **pdt) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); if (global.params.is64bit) verifyStructSize(Type::typeinfostruct, 17 * PTRSIZE); else verifyStructSize(Type::typeinfostruct, 15 * PTRSIZE); dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct dtsize_t(pdt, 0); // monitor assert(tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)tinfo; StructDeclaration *sd = tc->sym; /* Put out: * char[] name; * void[] init; * hash_t function(in void*) xtoHash; * bool function(in void*, in void*) xopEquals; * int function(in void*, in void*) xopCmp; * string function(const(void)*) xtoString; * uint m_flags; * //xgetMembers; * xdtor; * xpostblit; * uint m_align; * version (X86_64) * TypeInfo m_arg1; * TypeInfo m_arg2; * xgetRTInfo */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtsize_t(pdt, namelen); dtabytes(pdt, TYnptr, 0, namelen + 1, name); // void[] init; dtsize_t(pdt, sd->structsize); // init.length if (sd->zeroInit) dtsize_t(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0, TYnptr); // init.ptr FuncDeclaration *fd; FuncDeclaration *fdx; Dsymbol *s; static TypeFunction *tftohash; static TypeFunction *tftostring; if (!tftohash) { Scope sc; /* const hash_t toHash(); */ tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); tftohash->mod = MODconst; tftohash = (TypeFunction *)tftohash->semantic(0, &sc); tftostring = new TypeFunction(NULL, Type::tchar->invariantOf()->arrayOf(), 0, LINKd); tftostring = (TypeFunction *)tftostring->semantic(0, &sc); } TypeFunction *tfcmpptr; { Scope sc; /* const int opCmp(ref const KeyType s); */ Parameters *arguments = new Parameters; #if STRUCTTHISREF // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); #else // arg type is const T* Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); #endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(0, &sc); } s = search_function(sd, Id::tohash); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftohash); if (fd) { dtxoff(pdt, fd->toSymbol(), 0, TYnptr); TypeFunction *tf = (TypeFunction *)fd->type; assert(tf->ty == Tfunction); /* I'm a little unsure this is the right way to do it. Perhaps a better * way would to automatically add these attributes to any struct member * function with the name "toHash". * So I'm leaving this here as an experiment for the moment. */ if (!tf->isnothrow || tf->trust == TRUSTsystem /*|| tf->purity == PUREimpure*/) warning(fd->loc, "toHash() must be declared as extern (D) size_t toHash() const nothrow @safe, not %s", tf->toChars()); } else { //fdx->error("must be declared as extern (D) uint toHash()"); dtsize_t(pdt, 0); } } else dtsize_t(pdt, 0); if (sd->xeq) dtxoff(pdt, sd->xeq->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); s = search_function(sd, Id::cmp); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { //printf("test1 %s, %s, %s\n", fdx->toChars(), fdx->type->toChars(), tfeqptr->toChars()); fd = fdx->overloadExactMatch(tfcmpptr); if (fd) { dtxoff(pdt, fd->toSymbol(), 0, TYnptr); //printf("test2\n"); } else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); s = search_function(sd, Id::tostring); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftostring); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) char[] toString()"); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); // uint m_flags; size_t m_flags = tc->hasPointers(); dtsize_t(pdt, m_flags); #if DMDV2 #if 0 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xgetMembers #endif // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit && !(spostblit->storage_class & STCdisable)) dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xpostblit #endif // uint m_align; dtsize_t(pdt, tc->alignsize()); if (global.params.is64bit) { Type *t = sd->arg1type; for (int i = 0; i < 2; i++) { // m_argi if (t) { t->getTypeInfo(NULL); dtxoff(pdt, t->vtinfo->toSymbol(), 0, TYnptr); } else dtsize_t(pdt, 0); t = sd->arg2type; } } // xgetRTInfo if (sd->getRTInfo) sd->getRTInfo->toDt(pdt); else if (m_flags) dtsize_t(pdt, 1); // has pointers else dtsize_t(pdt, 0); // no pointers }
void TypeInfoStructDeclaration::toDt(dt_t **pdt) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); unsigned offset = Type::typeinfostruct->structsize; dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct dtsize_t(pdt, 0); // monitor assert(tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)tinfo; StructDeclaration *sd = tc->sym; /* Put out: * char[] name; * void[] init; * hash_t function(in void*) xtoHash; * bool function(in void*, in void*) xopEquals; * int function(in void*, in void*) xopCmp; * string function(const(void)*) xtoString; * uint m_flags; * xgetMembers; * xdtor; * xpostblit; * uint m_align; * version (X86_64) * TypeInfo m_arg1; * TypeInfo m_arg2; * * name[] */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtsize_t(pdt, namelen); //dtabytes(pdt, TYnptr, 0, namelen + 1, name); dtxoff(pdt, toSymbol(), offset, TYnptr); offset += namelen + 1; // void[] init; dtsize_t(pdt, sd->structsize); // init.length if (sd->zeroInit) dtsize_t(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0, TYnptr); // init.ptr FuncDeclaration *fd; FuncDeclaration *fdx; Dsymbol *s; static TypeFunction *tftohash; static TypeFunction *tftostring; if (!tftohash) { Scope sc; tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); tftohash->mod = MODconst; tftohash = (TypeFunction *)tftohash->semantic(0, &sc); tftostring = new TypeFunction(NULL, Type::tchar->invariantOf()->arrayOf(), 0, LINKd); tftostring = (TypeFunction *)tftostring->semantic(0, &sc); } TypeFunction *tfcmpptr; { Scope sc; Parameters *arguments = new Parameters; #if STRUCTTHISREF // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); #else // arg type is const T* Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); #endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(0, &sc); } s = search_function(sd, Id::tohash); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftohash); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) uint toHash()"); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); if (sd->xeq) dtxoff(pdt, sd->xeq->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); s = search_function(sd, Id::cmp); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { //printf("test1 %s, %s, %s\n", fdx->toChars(), fdx->type->toChars(), tfeqptr->toChars()); fd = fdx->overloadExactMatch(tfcmpptr); if (fd) { dtxoff(pdt, fd->toSymbol(), 0, TYnptr); //printf("test2\n"); } else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); s = search_function(sd, Id::tostring); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftostring); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) char[] toString()"); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); // uint m_flags; dtsize_t(pdt, tc->hasPointers()); #if DMDV2 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xgetMembers // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit && !(spostblit->storage_class & STCdisable)) dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xpostblit #endif // uint m_align; dtsize_t(pdt, tc->alignsize()); if (global.params.is64bit) { TypeTuple *tup = tc->toArgTypes(); assert(tup->arguments->dim <= 2); for (size_t i = 0; i < 2; i++) { if (i < tup->arguments->dim) { Type *targ = (tup->arguments->tdata()[i])->type; targ = targ->merge(); targ->getTypeInfo(NULL); dtxoff(pdt, targ->vtinfo->toSymbol(), 0, TYnptr); // m_argi } else dtsize_t(pdt, 0); // m_argi } } // name[] dtnbytes(pdt, namelen + 1, name); }
enum RET TypeFunction::retStyle() { //printf("TypeFunction::retStyle() %s\n", toChars()); #if DMDV2 if (isref) { //printf(" ref RETregs\n"); return RETregs; // returns a pointer } #endif Type *tn = next->toBasetype(); //printf("tn = %s\n", tn->toChars()); d_uns64 sz = tn->size(); Type *tns = tn; if (global.params.isWindows && global.params.is64bit) { // http://msdn.microsoft.com/en-us/library/7572ztz4(v=vs.80) if (tns->isscalar()) return RETregs; if (tns->ty == Tsarray) { do { tns = tns->nextOf()->toBasetype(); } while (tns->ty == Tsarray); } if (tns->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)tns)->sym; if (!sd->isPOD() || sz >= 8) return RETstack; } if (sz <= 16 && !(sz & (sz - 1))) return RETregs; return RETstack; } Lagain: if (tns->ty == Tsarray) { do { tns = tns->nextOf()->toBasetype(); } while (tns->ty == Tsarray); if (tns->ty != Tstruct) { L2: if (global.params.isLinux && linkage != LINKd && !global.params.is64bit) ; // 32 bit C/C++ structs always on stack else { switch (sz) { case 1: case 2: case 4: case 8: //printf(" sarray RETregs\n"); return RETregs; // return small structs in regs // (not 3 byte structs!) default: break; } } //printf(" sarray RETstack\n"); return RETstack; } } if (tns->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)tns)->sym; if (global.params.isLinux && linkage != LINKd && !global.params.is64bit) { //printf(" 2 RETstack\n"); return RETstack; // 32 bit C/C++ structs always on stack } if (sd->arg1type && !sd->arg2type) { tns = sd->arg1type; if (tns->ty != Tstruct) goto L2; goto Lagain; } else if (global.params.is64bit && !sd->arg1type && !sd->arg2type) return RETstack; else if (sd->isPOD()) { switch (sz) { case 1: case 2: case 4: case 8: //printf(" 3 RETregs\n"); return RETregs; // return small structs in regs // (not 3 byte structs!) case 16: if (!global.params.isWindows && global.params.is64bit) return RETregs; default: break; } } //printf(" 3 RETstack\n"); return RETstack; } else if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && linkage == LINKc && tns->iscomplex()) { if (tns->ty == Tcomplex32) return RETregs; // in EDX:EAX, not ST1:ST0 else return RETstack; } else { //assert(sz <= 16); //printf(" 4 RETregs\n"); return RETregs; } }
/*************************************** * This works by transforming a struct initializer into * a struct literal. In the future, the two should be the * same thing. */ Expression *StructInitializer::toExpression(Type *t) { Expression *e; size_t offset; //printf("StructInitializer::toExpression() %s\n", toChars()); if (!ad) // if fwd referenced return NULL; StructDeclaration *sd = ad->isStructDeclaration(); if (!sd) return NULL; Expressions *elements = new Expressions(); size_t nfields = ad->fields.dim - sd->isNested(); elements->setDim(nfields); for (size_t i = 0; i < elements->dim; i++) { (*elements)[i] = NULL; } size_t fieldi = 0; for (size_t i = 0; i < value.dim; i++) { Identifier *id = field[i]; if (id) { Dsymbol * s = ad->search(loc, id, 0); if (!s) { error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); goto Lerror; } s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { s->error("is not a per-instance initializable field"); goto Lerror; } if (s == ad->fields[fieldi]) break; } } else if (fieldi >= nfields) { error(loc, "too many initializers for '%s'", ad->toChars()); goto Lerror; } Initializer *iz = value[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) goto Lno; if ((*elements)[fieldi]) { error(loc, "duplicate initializer for field '%s'", ad->fields[fieldi]->toChars()); goto Lerror; } (*elements)[fieldi] = ex; ++fieldi; } // Now, fill in any missing elements with default initializers. // We also need to validate any anonymous unions offset = 0; for (size_t i = 0; i < elements->dim; ) { VarDeclaration * vd = ad->fields[i]->isVarDeclaration(); //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset); if (vd->offset < offset) { // Only the first field of a union can have an initializer if ((*elements)[i]) goto Lno; } else { if (!(*elements)[i]) { // Default initialize if (vd->init) { if (vd->scope) { // Do deferred semantic analysis Initializer *i2 = vd->init->syntaxCopy(); i2 = i2->semantic(vd->scope, vd->type, INITinterpret); (*elements)[i] = i2->toExpression(); if (!global.gag) { vd->scope = NULL; vd->init = i2; // save result } } else (*elements)[i] = vd->init->toExpression(); } else (*elements)[i] = vd->type->defaultInit(); } } offset = vd->offset + vd->type->size(); i++; #if 0 int unionSize = ad->numFieldsInUnion(i); if (unionSize == 1) { // Not a union -- default initialize if missing if (!(*elements)[i]) (*elements)[i] = vd->type->defaultInit(); } else { // anonymous union -- check for errors int found = -1; // index of the first field with an initializer for (size_t j = i; j < i + unionSize; ++j) { if (!(*elements)[j]) continue; if (found >= 0) { VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); error(loc, "%s cannot have initializers for fields %s and %s in same union", ad->toChars(), v1->toChars(), v->toChars()); goto Lerror; } found = j; } if (found == -1) { error(loc, "no initializer for union that contains field %s", vd->toChars()); goto Lerror; } } i += unionSize; #endif } for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (e && e->op == TOKerror) return e; } e = new StructLiteralExp(loc, sd, elements); e->type = sd->type; return e; Lno: delete elements; return NULL; Lerror: delete elements; return new ErrorExp(); }