Skip to content

Commit

Permalink
Resolve TypeInfo variables after semantic
Browse files Browse the repository at this point in the history
  • Loading branch information
yebblies committed May 17, 2015
1 parent 895eb9c commit e4658e4
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 98 deletions.
2 changes: 1 addition & 1 deletion src/backend.d
Expand Up @@ -22,7 +22,7 @@ extern extern (C++) void obj_start(char* srcfile);
extern extern (C++) void obj_end(Library library, File* objfile);
extern extern (C++) void obj_write_deferred(Library library);

extern extern (C++) Expression getTypeInfo(Type t, Scope* sc);
extern extern (C++) Type getTypeInfoType(Type t, Scope* sc);
extern extern (C++) Expression getInternalTypeInfo(Type t, Scope* sc);
extern extern (C++) void genObjFile(Module m, bool multiobj);
extern extern (C++) void genhelpers(Module m, bool multiobj);
Expand Down
20 changes: 18 additions & 2 deletions src/ctfeexpr.c
Expand Up @@ -331,7 +331,8 @@ UnionExp copyLiteral(Expression *e)
e->op == TOKvar || e->op == TOKdotvar ||
e->op == TOKint64 || e->op == TOKfloat64 ||
e->op == TOKchar || e->op == TOKcomplex80 ||
e->op == TOKvoid || e->op == TOKvector)
e->op == TOKvoid || e->op == TOKvector ||
e->op == TOKtypeid)
{
// Simple value types
// Keep e1 for DelegateExp and DotVarExp
Expand Down Expand Up @@ -1207,7 +1208,7 @@ bool isCtfeComparable(Expression *e)
return true;
}
// Bugzilla 14123: TypeInfo object is comparable in CTFE
if (e->op == TOKsymoff && ((SymOffExp *)e)->var->isTypeInfoDeclaration())
if (e->op == TOKtypeid)
return true;

return false;
Expand Down Expand Up @@ -1418,6 +1419,16 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2)
return 0;
return 1;
}
if (e1->op == TOKtypeid && e2->op == TOKtypeid)
{
// printf("e1: %s\n", e1->toChars());
// printf("e2: %s\n", e2->toChars());
Type *t1 = isType(((TypeidExp *)e1)->obj);
Type *t2 = isType(((TypeidExp *)e2)->obj);
assert(t1);
assert(t2);
return t1 != t2;
}

// null == null, regardless of type

Expand Down Expand Up @@ -2173,6 +2184,11 @@ bool isCtfeValueValid(Expression *newval)
Declaration *d = ((SymOffExp *)newval)->var;
return d->isFuncDeclaration() || d->isDataseg();
}
if (newval->op == TOKtypeid)
{
// always valid
return true;
}
if (newval->op == TOKaddress)
{
// e1 should be a CTFE reference
Expand Down
27 changes: 27 additions & 0 deletions src/e2ir.c
Expand Up @@ -1119,6 +1119,33 @@ elem *toElem(Expression *e, IRState *irs)
result = Dsymbol_toElem(de->declaration);
}

/***************************************
*/

void visit(TypeidExp *e)
{
//printf("TypeidExp::toElem() %s\n", e->toChars());
if (Type *t = isType(e->obj))
{
result = getTypeInfo(t, irs);
return;
}
if (Expression *ex = isExpression(e->obj))
{
Type *t = ex->type->toBasetype();
assert(t->ty == Tclass);
// generate **classptr to get the classinfo
result = toElem(ex, irs);
result = el_una(OPind,TYnptr,result);
result = el_una(OPind,TYnptr,result);
// Add extra indirection for interfaces
if (((TypeClass *)t)->sym->isInterfaceDeclaration())
result = el_una(OPind,TYnptr,result);
return;
}
assert(0);
}

/***************************************
*/

Expand Down
15 changes: 7 additions & 8 deletions src/expression.c
Expand Up @@ -48,7 +48,7 @@ Expression *expandVar(int result, VarDeclaration *v);
TypeTuple *toArgTypes(Type *t);
bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0);
Symbol *toInitializer(AggregateDeclaration *ad);
Expression *getTypeInfo(Type *t, Scope *sc);
Type *getTypeInfoType(Type *t, Scope *sc);

#define LOGSEMANTIC 0

Expand Down Expand Up @@ -6104,20 +6104,19 @@ Expression *TypeidExp::semantic(Scope *sc)
{
/* Get the dynamic type, which is .classinfo
*/
e = new DotIdExp(ea->loc, ea, Id::classinfo);
e = e->semantic(sc);
ea = ea->semantic(sc);
e = new TypeidExp(ea->loc, ea);
e->type = Type::typeinfoclass->type;
}
else if (ta->ty == Terror)
{
e = new ErrorExp();
}
else
{
/* Get the static type
*/
e = getTypeInfo(ta, sc);
if (e->loc.linnum == 0)
e->loc = loc; // so there's at least some line number info
// Handle this in the glue layer
e = new TypeidExp(loc, ta);
e->type = getTypeInfoType(ta, sc);
if (ea)
{
e = new CommaExp(loc, ea, e); // execute ea
Expand Down
11 changes: 0 additions & 11 deletions src/gluestub.c
Expand Up @@ -75,17 +75,6 @@ void backend_term()
{
}

// typinf

Expression *getTypeInfo(Type *t, Scope *sc)
{
Declaration *ti = new TypeInfoDeclaration(t, 1);
Expression *e = new VarExp(Loc(), ti);
e = e->addressOf();
e->type = ti->type;
return e;
}

// lib

Library *LibMSCoff_factory()
Expand Down
13 changes: 13 additions & 0 deletions src/inline.c
Expand Up @@ -895,6 +895,19 @@ Expression *doInline(Expression *e, InlineDoState *ids)
visit((Expression *)e);
}

void visit(TypeidExp *e)
{
//printf("TypeidExp::doInline(): %s\n", e->toChars());
TypeidExp *te = (TypeidExp *)e->copy();
if (Expression *ex = isExpression(te->obj))
{
te->obj = doInline(ex, ids);
}
else
assert(isType(te->obj));
result = te;
}

void visit(NewExp *e)
{
//printf("NewExp::doInline(): %s\n", e->toChars());
Expand Down
140 changes: 74 additions & 66 deletions src/interpret.c
Expand Up @@ -2543,6 +2543,45 @@ class Interpreter : public Visitor
#endif
}

void visit(TypeidExp *e)
{
#if LOG
printf("%s TypeidExp::interpret() %s\n", e->loc.toChars(), e->toChars());
#endif
if (Type *t = isType(e->obj))
{
result = e;
return;
}
if (Expression *ex = isExpression(e->obj))
{
result = interpret(ex, istate);
if (exceptionOrCant(ex))
return;

if (result->op == TOKnull)
{
e->error("null pointer dereference evaluating typeid. '%s' is null", ex->toChars());
result = CTFEExp::cantexp;
return;
}
if (result->op != TOKclassreference)
{
e->error("CTFE internal error: determining classinfo");
result = CTFEExp::cantexp;
return;
}

ClassDeclaration *cd = ((ClassReferenceExp *)result)->originalClass();
assert(cd);

result = new TypeidExp(e->loc, cd->type);
result->type = e->type;
return;
}
visit((Expression *)e);
}

void visit(TupleExp *e)
{
#if LOG
Expand Down Expand Up @@ -4690,36 +4729,39 @@ class Interpreter : public Visitor
pthis = ((DotTypeExp *)dve->e1)->e1;

// Special handling for: typeid(T[n]).destroy(ea)
TypeInfoDeclaration *tid;
if (pthis->op == TOKsymoff &&
(tid = ((SymOffExp *)pthis)->var->isTypeInfoDeclaration()) != NULL &&
tid->tinfo->toBasetype()->ty == Tsarray &&
fd->ident == Id::destroy &&
e->arguments->dim == 1)
{
Type *tb = tid->tinfo->baseElemOf();
if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->dtor)
if (pthis->op == TOKtypeid)
{
TypeidExp *tie = (TypeidExp *)pthis;
Type *t = isType(tie->obj);
if (t &&
t->toBasetype()->ty == Tsarray &&
fd->ident == Id::destroy &&
e->arguments->dim == 1)
{
Expression *ea = (*e->arguments)[0];
// ea would be:
// &var <-- SymOffExp
// cast(void*)&var
// cast(void*)&this.field
// etc.
if (ea->op == TOKcast)
ea = ((CastExp *)ea)->e1;
if (ea->op == TOKsymoff)
result = getVarExp(e->loc, istate, ((SymOffExp *)ea)->var, ctfeNeedRvalue);
else if (ea->op == TOKaddress)
result = interpret(((AddrExp *)ea)->e1, istate);
else
assert(0);
if (CTFEExp::isCantExp(result))
Type *tb = t->baseElemOf();
if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->dtor)
{
Expression *ea = (*e->arguments)[0];
// ea would be:
// &var <-- SymOffExp
// cast(void*)&var
// cast(void*)&this.field
// etc.
if (ea->op == TOKcast)
ea = ((CastExp *)ea)->e1;
if (ea->op == TOKsymoff)
result = getVarExp(e->loc, istate, ((SymOffExp *)ea)->var, ctfeNeedRvalue);
else if (ea->op == TOKaddress)
result = interpret(((AddrExp *)ea)->e1, istate);
else
assert(0);
if (CTFEExp::isCantExp(result))
return;
result = evaluateDtor(istate, result);
if (!result)
result = CTFEExp::voidexp;
return;
result = evaluateDtor(istate, result);
if (!result)
result = CTFEExp::voidexp;
return;
}
}
}
}
Expand Down Expand Up @@ -4771,15 +4813,11 @@ class Interpreter : public Visitor
// Currently this is satisfied because closure is not yet supported.
assert(!fd->isNested());

// 'typeid(T)' for the class type T is kept as SymOffExp.
// Therefore try to resolve it here and report CTFE error.
if (pthis->op == TOKsymoff)
if (pthis->op == TOKtypeid)
{
VarDeclaration *vthis = ((SymOffExp *)pthis)->var->isVarDeclaration();
assert(vthis);
pthis = getVarExp(e->loc, istate, vthis, ctfeNeedLvalue);
if (exceptionOrCant(pthis))
return;
pthis->error("static variable %s cannot be read at compile time", pthis->toChars());
result = CTFEExp::cantexp;
return;
}
assert(pthis);

Expand Down Expand Up @@ -5774,36 +5812,6 @@ class Interpreter : public Visitor
}
}

// Check for .classinfo, which is lowered in the semantic pass into **(class).
if (e->e1->op == TOKstar && e->e1->type->ty == Tpointer && isTypeInfo_Class(e->e1->type->nextOf()))
{
result = interpret(((PtrExp *)e->e1)->e1, istate);
if (exceptionOrCant(result))
return;
if (result->op == TOKnull)
{
e->error("null pointer dereference evaluating typeid. '%s' is null", ((PtrExp *)e->e1)->e1->toChars());
result = CTFEExp::cantexp;
return;
}
if (result->op != TOKclassreference)
{
e->error("CTFE internal error: determining classinfo");
result = CTFEExp::cantexp;
return;
}
ClassDeclaration *cd = ((ClassReferenceExp *)result)->originalClass();
assert(cd);

// Create the classinfo, if it doesn't yet exist.
// TODO: This belongs in semantic, CTFE should not have to do this.
if (!cd->vclassinfo)
cd->vclassinfo = new TypeInfoClassDeclaration(cd->type);
result = new SymOffExp(e->loc, cd->vclassinfo, 0);
result->type = e->type;
return;
}

// It's possible we have an array bounds error. We need to make sure it
// errors with this line number, not the one where the pointer was set.
result = interpret(e->e1, istate);
Expand Down
14 changes: 14 additions & 0 deletions src/todt.c
Expand Up @@ -32,6 +32,7 @@
#include "ctfe.h"
#include "arraytypes.h"
#include "visitor.h"
#include "template.h"
// Back end
#include "dt.h"

Expand All @@ -53,6 +54,7 @@ void toObjFile(Dsymbol *ds, bool multiobj);
Symbol *toVtblSymbol(ClassDeclaration *cd);
Symbol* toSymbol(StructLiteralExp *sle);
Symbol* toSymbol(ClassReferenceExp *cre);
void genTypeInfo(Type *t, Scope *sc);

/* ================================================================ */

Expand Down Expand Up @@ -589,6 +591,18 @@ dt_t **Expression_toDt(Expression *e, dt_t **pdt)
}
pdt = ClassReferenceExp_toDt(e, pdt, 0);
}

void visit(TypeidExp *e)
{
if (Type *t = isType(e->obj))
{
genTypeInfo(t, NULL);
Symbol *s = toSymbol(t->vtinfo);
pdt = dtxoff(pdt, s, 0);
return;
}
assert(0);
}
};

ExpToDt v(pdt);
Expand Down

0 comments on commit e4658e4

Please sign in to comment.