Skip to content

Commit

Permalink
Merge pull request #573 from donc/ctfe6984
Browse files Browse the repository at this point in the history
CTFE: 6984 7143 7144
  • Loading branch information
WalterBright committed Dec 21, 2011
2 parents 641c83f + e59b880 commit feac8ea
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 43 deletions.
1 change: 1 addition & 0 deletions src/declaration.h
Expand Up @@ -557,6 +557,7 @@ struct FuncDeclaration : Declaration
int inlineNest; // !=0 if nested inline
int isArrayOp; // !=0 if array operation
enum PASS semanticRun;
int semantic3Errors; // !=0 if errors in semantic3
// this function's frame ptr
ForeachStatement *fes; // if foreach body, this is the foreach
int introducing; // !=0 if 'introducing' function
Expand Down
5 changes: 5 additions & 0 deletions src/func.c
Expand Up @@ -68,6 +68,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla
inlineNest = 0;
isArrayOp = 0;
semanticRun = PASSinit;
semantic3Errors = 0;
#if DMDV1
nestedFrameRef = 0;
#endif
Expand Down Expand Up @@ -827,6 +828,7 @@ void FuncDeclaration::semantic3(Scope *sc)
if (semanticRun >= PASSsemantic3)
return;
semanticRun = PASSsemantic3;
semantic3Errors = 0;

if (!type || type->ty != Tfunction)
return;
Expand Down Expand Up @@ -1645,7 +1647,10 @@ void FuncDeclaration::semantic3(Scope *sc)
if (global.gag && global.errors != nerrors)
semanticRun = PASSsemanticdone; // Ensure errors get reported again
else
{
semanticRun = PASSsemantic3done;
semantic3Errors = global.errors - nerrors;
}
//printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars());
//fflush(stdout);
}
Expand Down
108 changes: 65 additions & 43 deletions src/interpret.c
Expand Up @@ -736,7 +736,8 @@ Expression *UnrolledLoopStatement::interpret(InterState *istate)
// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer.
int isTrueBool(Expression *e)
{
return e->isBool(TRUE) || (e->type->ty == Tpointer && e->op != TOKnull);
return e->isBool(TRUE) || ((e->type->ty == Tpointer || e->type->ty == Tclass)
&& e->op != TOKnull);
}

Expression *IfStatement::interpret(InterState *istate)
Expand Down Expand Up @@ -2687,6 +2688,22 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex
return new IntegerExp(loc, cmp, type);
}

Expression *ctfeIdentity(enum TOK op, Type *type, Expression *e1, Expression *e2)
{
if (e1->op == TOKclassreference || e2->op == TOKclassreference)
{
int cmp = 0;
if (e1->op == TOKclassreference && e2->op == TOKclassreference &&
((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value)
cmp = 1;
if (op == TOKnotidentity || op == TOKnotequal)
cmp ^= 1;
return new IntegerExp(e1->loc, cmp, type);
}
return Identity(op, type, e1, e2);
}


Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp)
{ Expression *e;
Expression *e1;
Expand Down Expand Up @@ -2722,7 +2739,8 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp
e1->op != TOKnull &&
e1->op != TOKstring &&
e1->op != TOKarrayliteral &&
e1->op != TOKstructliteral)
e1->op != TOKstructliteral &&
e1->op != TOKclassreference)
{
error("cannot compare %s at compile time", e1->toChars());
goto Lcant;
Expand All @@ -2737,7 +2755,8 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp
e2->op != TOKnull &&
e2->op != TOKstring &&
e2->op != TOKarrayliteral &&
e2->op != TOKstructliteral)
e2->op != TOKstructliteral &&
e1->op != TOKclassreference)
{
error("cannot compare %s at compile time", e2->toChars());
goto Lcant;
Expand All @@ -2751,15 +2770,15 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp
return EXP_CANT_INTERPRET;
}

#define BIN_INTERPRET2(op) \
#define BIN_INTERPRET2(op, opfunc) \
Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \
{ \
return interpretCommon2(istate, goal, &op); \
return interpretCommon2(istate, goal, &opfunc); \
}

BIN_INTERPRET2(Equal)
BIN_INTERPRET2(Identity)
BIN_INTERPRET2(Cmp)
BIN_INTERPRET2(Equal, Equal)
BIN_INTERPRET2(Identity, ctfeIdentity)
BIN_INTERPRET2(Cmp, Cmp)

/* Helper functions for BinExp::interpretAssignCommon
*/
Expand Down Expand Up @@ -4491,12 +4510,6 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal)
printf("CallExp::interpret() %s\n", toChars());
#endif

if (global.errors)
{
error("CTFE failed because of previous errors");
return EXP_CANT_INTERPRET;
}

Expression * pthis = NULL;
FuncDeclaration *fd = NULL;
Expression *ecall = e1;
Expand Down Expand Up @@ -4588,51 +4601,60 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal)
}
if (pthis)
{ // Member function call
Expression *oldpthis;
if (pthis->op == TOKthis)
{
pthis = istate ? istate->localThis : NULL;
oldpthis == pthis;
}
else
{
if (pthis->op == TOKcomma)
pthis = pthis->interpret(istate);
if (exceptionOrCantInterpret(pthis))
return pthis;
// Evaluate 'this'
Expression *oldpthis = pthis;
oldpthis = pthis;
if (pthis->op != TOKvar)
pthis = pthis->interpret(istate, ctfeNeedLvalue);
if (exceptionOrCantInterpret(pthis))
return pthis;
if (fd->isVirtual())
{ // Make a virtual function call.
Expression *thisval = pthis;
if (pthis->op == TOKvar)
{ assert(((VarExp*)thisval)->var->isVarDeclaration());
thisval = ((VarExp*)thisval)->var->isVarDeclaration()->getValue();
}
// Get the function from the vtable of the original class
ClassDeclaration *cd;
if (thisval && thisval->op == TOKnull)
{
error("function call through null class reference %s", pthis->toChars());
return EXP_CANT_INTERPRET;
}
if (oldpthis->op == TOKsuper)
{ assert(oldpthis->type->ty == Tclass);
cd = ((TypeClass *)oldpthis->type)->sym;
}
else
{
assert(thisval && thisval->op == TOKclassreference);
cd = ((ClassReferenceExp *)thisval)->originalClass();
}
// We can't just use the vtable index to look it up, because
// vtables for interfaces don't get populated until the glue layer.
fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type);

assert(fd);
}
if (fd->isVirtual())
{ // Make a virtual function call.
Expression *thisval = pthis;
if (pthis->op == TOKvar)
{ assert(((VarExp*)thisval)->var->isVarDeclaration());
thisval = ((VarExp*)thisval)->var->isVarDeclaration()->getValue();
}
// Get the function from the vtable of the original class
ClassDeclaration *cd;
if (thisval && thisval->op == TOKnull)
{
error("function call through null class reference %s", pthis->toChars());
return EXP_CANT_INTERPRET;
}
if (oldpthis->op == TOKsuper)
{ assert(oldpthis->type->ty == Tclass);
cd = ((TypeClass *)oldpthis->type)->sym;
}
else
{
assert(thisval && thisval->op == TOKclassreference);
cd = ((ClassReferenceExp *)thisval)->originalClass();
}
// We can't just use the vtable index to look it up, because
// vtables for interfaces don't get populated until the glue layer.
fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type);

assert(fd);
}
}
if (fd && fd->semanticRun >= PASSsemantic3done && fd->semantic3Errors)
{
error("CTFE failed because of previous errors in %s", fd->toChars());
return EXP_CANT_INTERPRET;
}
// Check for built-in functions
Expression *eresult = evaluateIfBuiltin(istate, loc, fd, arguments, pthis);
if (eresult)
Expand Down
83 changes: 83 additions & 0 deletions test/compilable/interpret3.d
Expand Up @@ -3644,3 +3644,86 @@ static assert( {
int i = 416;
return bug7043!(char)(i);
}() == 416 );

/**************************************************
7143 'is' for classes
**************************************************/

class C7143
{
int x;
}

int bug7143(int test)
{
C7143 c = new C7143;
C7143 d = new C7143;
if (test == 1)
{
if (c)
return c.x + 8;
return -1;
}
if (test == 2)
{
if(c is null)
return -1;
return c.x + 45;
}
if (test == 3)
{
if (c is c)
return 58;
}
if (test == 4)
{
if (c !is c)
return -1;
else
return 48;
}
if (test == 6)
d = c;
if (test == 5 || test == 6)
{
if (c is d)
return 188;
else
return 48;
}
return -1;
}

static assert(bug7143(1) == 8);
static assert(bug7143(2) == 45);
static assert(bug7143(3) == 58);
static assert(bug7143(4) == 48);
static assert(bug7143(5) == 48);
static assert(bug7143(6) == 188);

/**************************************************
7147 virtual function calls from base class
**************************************************/

class A7147
{
int foo() { return 0; }

int callfoo()
{
return foo();
}
}

class B7147 : A7147
{
override int foo() { return 1; }
}

int test7147()
{
A7147 a = new B7147;
return a.callfoo();
}

static assert(test7147() == 1);

0 comments on commit feac8ea

Please sign in to comment.