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 source_name(Dsymbol *s) { char *name = s->ident->toChars(); TemplateInstance *ti = s->isTemplateInstance(); if (ti) { if (!substitute(ti->tempdecl)) { store(ti->tempdecl); name = ti->name->toChars(); buf.printf("%d%s", strlen(name), name); } buf.writeByte('I'); bool is_var_arg = false; for (size_t i = 0; i < ti->tiargs->dim; i++) { RootObject *o = (RootObject *)(*ti->tiargs)[i]; TemplateParameter *tp = NULL; TemplateValueParameter *tv = NULL; TemplateTupleParameter *tt = NULL; if (!is_var_arg) { TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); tp = (*td->parameters)[i]; tv = tp->isTemplateValueParameter(); tt = tp->isTemplateTupleParameter(); } /* * <template-arg> ::= <type> # type or template * ::= <expr-primary> # simple expressions */ if (tt) { buf.writeByte('I'); is_var_arg = true; tp = NULL; } if (tv) { // <expr-primary> ::= L <type> <value number> E # integer literal if (tv->valType->isintegral()) { Expression* e = isExpression(o); assert(e); buf.writeByte('L'); tv->valType->accept(this); if (tv->valType->isunsigned()) { buf.printf("%llu", e->toUInteger()); } else { dinteger_t val = e->toInteger(); if (val < 0) { val = -val; buf.writeByte('n'); } buf.printf("%lld", val); } buf.writeByte('E'); } else { s->error("ICE: C++ %s template value parameter is not supported", tv->valType->toChars()); assert(0); } } else if (!tp || tp->isTemplateTypeParameter()) { Type *t = isType(o); assert(t); t->accept(this); } else if (tp->isTemplateAliasParameter()) { Dsymbol* d = isDsymbol(o); Expression* e = isExpression(o); if (!d && !e) { s->error("ICE: %s is unsupported parameter for C++ template: (%s)", o->toChars()); assert(0); } if (d && d->isFuncDeclaration()) { bool is_nested = d->toParent() && !d->toParent()->isModule() && ((TypeFunction *)d->isFuncDeclaration()->type)->linkage == LINKcpp; if (is_nested) buf.writeByte('X'); buf.writeByte('L'); mangle_function(d->isFuncDeclaration()); buf.writeByte('E'); if (is_nested) buf.writeByte('E'); } else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration()) { VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration(); buf.writeByte('L'); mangle_variable(vd, true); buf.writeByte('E'); } else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember) { if (!substitute(d)) { cpp_mangle_name(d); store(d); } } else { s->error("ICE: %s is unsupported parameter for C++ template", o->toChars()); assert(0); } } else { s->error("ICE: C++ templates support only integral value , type parameters, alias templates and alias function parameters"); assert(0); } } if (is_var_arg) { buf.writeByte('E'); } buf.writeByte('E'); return; } else { buf.printf("%d%s", strlen(name), name); } }