void CompileDeclaration::compileIt(Scope *sc) { //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); sc = sc->startCTFE(); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); sc = sc->endCTFE(); if (exp->op != TOKerror) { Expression *e = exp->ctfeInterpret(); StringExp *se = e->toStringExp(); if (!se) exp->error("argument to mixin must be a string, not (%s) of type %s", exp->toChars(), exp->type->toChars()); else { se = se->toUTF8(sc); unsigned errors = global.errors; Parser p(loc, sc->module, (utf8_t *)se->string, se->len, 0); p.nextToken(); decl = p.parseDeclDefs(0); if (p.token.value != TOKeof) exp->error("incomplete mixin declaration (%s)", se->toChars()); if (p.errors) { assert(global.errors != errors); decl = NULL; } } } }
String2(const StringExp<S,L,R>& exp) : mdata(exp.size() + 1) { S* dest = mdata.GetArray(); exp.append(dest); *dest = 0; }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue; int olderrors = global.errors; exp = exp->optimize(wantOptimize); 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(); /* 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); L1: exp = exp->optimize(wantOptimize); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->optimize(WANTvalue | WANTinterpret); 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 (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); L1: exp = exp->optimize(WANTvalue | WANTinterpret); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
void CompileDeclaration::compileIt(Scope *sc) { //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->ctfeInterpret(); StringExp *se = exp->toString(); if (!se) { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); } else { se = se->toUTF8(sc); Parser p(sc->module, (unsigned char *)se->string, se->len, 0); p.loc = loc; p.nextToken(); decl = p.parseDeclDefs(0); if (p.token.value != TOKeof) exp->error("incomplete mixin declaration (%s)", se->toChars()); } }
void CompileDeclaration::compileIt(Scope *sc) { //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->optimize(WANTvalue | WANTinterpret); if (exp->op != TOKstring) { /* exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); */ } else { StringExp *se = (StringExp *)exp; se = se->toUTF8(sc); Parser p(sc->module, (unsigned char *)se->string, se->len, 0); p.loc = loc; p.nextToken(); decl = p.parseDeclDefs(0); /* if (p.token.value != TOKeof) exp->error("incomplete mixin declaration (%s)", se->toChars()); */ } }
void visit(PragmaDeclaration *pd) { if (pd->ident == Id::lib) { assert(pd->args && pd->args->dim == 1); Expression *e = (*pd->args)[0]; assert(e->op == TOKstring); StringExp *se = (StringExp *)e; char *name = (char *)mem.xmalloc(se->numberOfCodeUnits() + 1); se->writeTo(name, true); /* Embed the library names into the object file. * The linker will then automatically * search that library, too. */ if (!obj_includelib(name)) { /* The format does not allow embedded library names, * so instead append the library name to the list to be passed * to the linker. */ global.params.libfiles->push(name); } } else if (pd->ident == Id::startaddress) { assert(pd->args && pd->args->dim == 1); Expression *e = (*pd->args)[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); Symbol *s = toSymbol(f); obj_startaddress(s); } visit((AttribDeclaration *)pd); }
/** \name Visit Constant Expressions nodes. ** \{ */ void PrintVisitor::visit (const StringExp &e) { if (types::InternalType * pIT = e.getConstant()) { types::String * pStr = static_cast<types::String *>(pIT); if (pStr->getSize() == 0) { *ostr << L"[]"; } if (pStr->getSize() == 1) { std::wstring wstr(pStr->get(0, 0)); printString(wstr); } else { *ostr << L"["; const int r = pStr->getRows(); const int c = pStr->getCols(); for (int i = 0; i < r; ++i) { for (int j = 0; j < c - 1; ++j) { std::wstring wstr(pStr->get(i, j)); printString(wstr); *ostr << L" "; } std::wstring wstr(pStr->get(i, c - 1)); printString(wstr); *ostr << L";"; } *ostr << L"]"; } } else { printString(e.getValue()); } }
void visit(PragmaDeclaration *decl) override { if (decl->ident == Id::lib) { assert(decl->args && decl->args->dim == 1); assert(!irs->dcomputetarget); Expression *e = static_cast<Expression *>(decl->args->data[0]); assert(e->op == TOKstring); StringExp *se = static_cast<StringExp *>(e); const std::string name(se->toPtr(), se->numberOfCodeUnits()); auto nameLen = name.size(); if (global.params.targetTriple->isWindowsGNUEnvironment()) { if (nameLen > 4 && !memcmp(&name[nameLen - 4], ".lib", 4)) { // On MinGW, strip the .lib suffix, if any, to improve // compatibility with code written for DMD (we pass the name to GCC // via -l, just as on Posix). nameLen -= 4; } if (nameLen >= 7 && !memcmp(name.data(), "shell32", 7)) { // Another DMD compatibility kludge: Ignore // pragma(lib, "shell32.lib"), it is implicitly provided by // MinGW. return; } } // With LLVM 3.3 or later we can place the library name in the object // file. This seems to be supported only on Windows. if (global.params.targetTriple->isWindowsMSVCEnvironment()) { llvm::SmallString<24> LibName(name); // Win32: /DEFAULTLIB:"curl" if (LibName.endswith(".a")) { LibName = LibName.substr(0, LibName.size() - 2); } if (LibName.endswith(".lib")) { LibName = LibName.substr(0, LibName.size() - 4); } llvm::SmallString<24> tmp("/DEFAULTLIB:\""); tmp.append(LibName); tmp.append("\""); LibName = tmp; // Embed library name as linker option in object file auto Value = llvm::MDString::get(gIR->context(), LibName); gIR->LinkerMetadataArgs.push_back( llvm::MDNode::get(gIR->context(), Value)); } else { size_t const n = nameLen + 3; char *arg = static_cast<char *>(mem.xmalloc(n)); arg[0] = '-'; arg[1] = 'l'; memcpy(arg + 2, name.data(), nameLen); arg[n - 1] = 0; global.params.linkswitches.push(arg); } } visit(static_cast<AttribDeclaration *>(decl)); }
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); if (needInterpret) exp = exp->ctfeSemantic(sc); else 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()); 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; }
DValue *DtoInlineAsmExpr(Loc &loc, FuncDeclaration *fd, Expressions *arguments, LLValue *sretPointer) { IF_LOG Logger::println("DtoInlineAsmExpr @ %s", loc.toChars()); LOG_SCOPE; assert(fd->toParent()->isTemplateInstance() && "invalid inline __asm expr"); assert(arguments->dim >= 2 && "invalid __asm call"); // get code param Expression *e = (*arguments)[0]; IF_LOG Logger::println("code exp: %s", e->toChars()); StringExp *se = static_cast<StringExp *>(e); if (e->op != TOKstring || se->sz != 1) { e->error("`__asm` code argument is not a `char[]` string literal"); fatal(); } std::string code(se->toPtr(), se->numberOfCodeUnits()); // get constraints param e = (*arguments)[1]; IF_LOG Logger::println("constraint exp: %s", e->toChars()); se = static_cast<StringExp *>(e); if (e->op != TOKstring || se->sz != 1) { e->error("`__asm` constraints argument is not a `char[]` string literal"); fatal(); } std::string constraints(se->toPtr(), se->numberOfCodeUnits()); // build runtime arguments size_t n = arguments->dim; LLSmallVector<llvm::Value *, 8> args; args.reserve(n - 2); std::vector<LLType *> argtypes; argtypes.reserve(n - 2); for (size_t i = 2; i < n; i++) { args.push_back(DtoRVal((*arguments)[i])); argtypes.push_back(args.back()->getType()); } // build asm function type Type *type = fd->type->nextOf(); LLType *ret_type = DtoType(type->toBasetype()); llvm::FunctionType *FT = llvm::FunctionType::get(ret_type, argtypes, false); // make sure the constraints are valid if (!llvm::InlineAsm::Verify(FT, constraints)) { e->error("`__asm` constraint argument is invalid"); fatal(); } // build asm call bool sideeffect = true; llvm::InlineAsm *ia = llvm::InlineAsm::get(FT, code, constraints, sideeffect); llvm::Value *rv = gIR->ir->CreateCall(ia, args, ""); if (sretPointer) { DtoStore(rv, DtoBitCast(sretPointer, getPtrToType(ret_type))); return new DLValue(type, sretPointer); } // work around missing tuple support for users of the return value if (type->ty == Tstruct) { // make a copy llvm::Value *mem = DtoAlloca(type, ".__asm_tuple_ret"); DtoStore(rv, DtoBitCast(mem, getPtrToType(ret_type))); return new DLValue(type, mem); } // return call as im value return new DImValue(type, rv); }
int compare(RootObject *obj) override { Case *c2 = static_cast<Case *>(obj); return str->compare(c2->str); }
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->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(); } 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); } if (exp->op == TOKerror) return this; L1: if (needInterpret) exp = exp->ctfeInterpret(); else exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; }
Expression *TraitsExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("TraitsExp::semantic() %s\n", toChars()); #endif if (ident != Id::compiles && ident != Id::isSame) TemplateInstance::semanticTiargs(loc, sc, args, 1); size_t dim = args ? args->dim : 0; Object *o; FuncDeclaration *f; #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ { Type *t = getType((Object *)args->data[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((Object *)args->data[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::isAbstractFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) } else if (ident == Id::isVirtualFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual()) } else if (ident == Id::isFinalFunction) { ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal()) } else if (ident == Id::hasMember || ident == Id::getMember || ident == Id::getVirtualFunctions) { if (dim != 2) goto Ldimerror; Object *o = (Object *)args->data[0]; Expression *e = isExpression((Object *)args->data[1]); if (!e) { // error("expression expected as second argument of __traits %s", ident->toChars()); goto Lfalse; } e = e->optimize(WANTvalue | WANTinterpret); if (e->op != TOKstring) { // error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars()); goto Lfalse; } StringExp *se = (StringExp *)e; se = se->toUTF8(sc); if (se->sz != 1) { // error("string must be chars"); goto Lfalse; } Identifier *id = Lexer::idPool((char *)se->string); Type *t = isType(o); e = isExpression(o); Dsymbol *s = isDsymbol(o); if (t) e = new TypeDotIdExp(loc, t, id); else if (e) e = new DotIdExp(loc, e, id); else if (s) { e = new DsymbolExp(loc, s); e = new DotIdExp(loc, e, id); } else { // error("invalid first argument"); goto Lfalse; } if (ident == Id::hasMember) { /* Take any errors as meaning it wasn't found */ unsigned errors = global.errors; global.gag++; e = e->semantic(sc); global.gag--; if (errors != global.errors) { if (global.gag == 0) global.errors = errors; goto Lfalse; } else goto Ltrue; } else if (ident == Id::getMember) { e = e->semantic(sc); return e; } else if (ident == Id::getVirtualFunctions) { 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 virtual function overloads of e */ //e->dump(0); Expressions *exps = new Expressions(); FuncDeclaration *f; if (e->op == TOKvar) { VarExp *ve = (VarExp *)e; f = ve->var->isFuncDeclaration(); } else if (e->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)e; f = dve->var->isFuncDeclaration(); } else f = NULL; Pvirtuals p; p.exps = exps; p.e1 = e; overloadApply(f, fpvirtuals, &p); TupleExp *tup = new TupleExp(loc, exps); return tup->semantic(sc); } else assert(0); } else if (ident == Id::classInstanceSize) { if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[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::allMembers || ident == Id::derivedMembers) { if (dim != 1) goto Ldimerror; Object *o = (Object *)args->data[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sd; if (!s) { // error("argument has no members"); goto Lfalse; } if ((sd = s->isScopeDsymbol()) == NULL) { // error("%s %s has no members", s->kind(), s->toChars()); goto Lfalse; } Expressions *exps = new Expressions; while (1) { size_t dim = ScopeDsymbol::dim(sd->members); for (size_t i = 0; i < dim; i++) { Dsymbol *sm = ScopeDsymbol::getNth(sd->members, i); //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { //printf("\t%s\n", sm->ident->toChars()); char *str = sm->ident->toChars(); /* Skip if already present in exps[] */ for (size_t j = 0; j < exps->dim; j++) { StringExp *se2 = (StringExp *)exps->data[j]; if (strcmp(str, (char *)se2->string) == 0) goto Lnext; } StringExp *se = new StringExp(loc, str); exps->push(se); } Lnext: ; } ClassDeclaration *cd = sd->isClassDeclaration(); if (cd && cd->baseClass && ident == Id::allMembers) sd = cd->baseClass; // do again with base class else break; } Expression *e = new ArrayLiteralExp(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++) { Object *o = (Object *)args->data[i]; Type *t; Expression *e; Dsymbol *s; unsigned errors = global.errors; global.gag++; t = isType(o); if (t) { t->resolve(loc, sc, &e, &t, &s); if (t) t->semantic(loc, sc); else if (e) e->semantic(sc); } else { e = isExpression(o); if (e) e->semantic(sc); } global.gag--; if (errors != global.errors) { if (global.gag == 0) global.errors = errors; 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); Object *o1 = (Object *)args->data[0]; Object *o2 = (Object *)args->data[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); #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 && ea1->equals(ea2)) goto Ltrue; } if (!s1 || !s2) goto Lfalse; s1 = s1->toAlias(); s2 = s2->toAlias(); if (s1 == s2) goto Ltrue; else goto Lfalse; } else { // error("unrecognized trait %s", ident->toChars()); goto Lfalse; } return NULL; Lnottype: // error("%s is not a type", o->toChars()); goto Lfalse; Ldimerror: // error("wrong number of arguments %d", dim); goto Lfalse; Lfalse: return new IntegerExp(loc, 0, Type::tbool); Ltrue: return new IntegerExp(loc, 1, Type::tbool); }
void PragmaDeclaration::semantic(Scope *sc) { // Should be merged with PragmaStatement #if IN_LLVM Pragma llvm_internal = LLVMnone; std::string arg1str; #endif //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) { se = se->toUTF8(sc); 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(); 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 { /* Bugzilla 11980: * resolveProperties and ctfeInterpret call are not necessary. */ Expression *e = (*args)[0]; sc = sc->startCTFE(); e = e->semantic(sc); sc = sc->endCTFE(); (*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 } } #if IN_LLVM else if ((llvm_internal = DtoGetPragma(sc, this, arg1str)) != LLVMnone) { // nothing to do anymore } #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]; #if IN_LLVM // ignore errors in ignored pragmas. global.gag++; unsigned errors_save = global.errors; #endif 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 IN_LLVM // restore error state. global.gag--; global.errors = errors_save; #endif } if (args->dim) fprintf(global.stdmsg, ")"); } fprintf(global.stdmsg, "\n"); } } 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"); } #if IN_LLVM else { DtoCheckPragma(this, s, llvm_internal, arg1str); } #endif } } return; Lnodecl: if (decl) { error("pragma is missing closing ';'"); goto Ldecl; // do them anyway, to avoid segfaults. } }
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::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); PROT protection = s->prot(); const char *protName = Pprotectionnames[protection]; 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 = Lexer::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; } //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttributes, s->userAttributesScope); 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) { 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(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(); unsigned oldspec = global.speculativeGag; global.speculativeGag = global.gag; Scope *sc2 = sc->push(); sc2->speculative = true; sc2->flags = sc->flags & ~SCOPEctfe | 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); ex = checkGC(sc2, ex); if (ex->op == TOKerror) err = true; } sc2->pop(); global.speculativeGag = oldspec; 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 (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); }
/*************************************** * 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; }