Skip to content

Commit

Permalink
fix Issue 11042 - Inconsistent "static condition" behaviors
Browse files Browse the repository at this point in the history
Divide `SCOPEcondition` and `SCOPEconstraint` properly.
  • Loading branch information
9rnsr committed Aug 31, 2014
1 parent f6c130e commit 2968596
Show file tree
Hide file tree
Showing 12 changed files with 57 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/cond.c
Expand Up @@ -337,7 +337,7 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
sc = sc->push(sc->scopesym);
sc->sds = sds; // sds gets any addMember()
//sc->speculative = true; // TODO: static if (is(T U)) { /* U is available */ }
sc->flags |= SCOPEstaticif;
sc->flags |= SCOPEcondition;

sc = sc->startCTFE();
Expression *e = exp->semantic(sc);
Expand Down
6 changes: 3 additions & 3 deletions src/expression.c
Expand Up @@ -5901,7 +5901,7 @@ Expression *IsExp::semantic(Scope *sc)
*/

//printf("IsExp::semantic(%s)\n", toChars());
if (id && !(sc->flags & (SCOPEstaticif | SCOPEstaticassert)))
if (id && !(sc->flags & SCOPEcondition))
{
error("can only declare type aliases within static if conditionals or static asserts");
return new ErrorExp();
Expand Down Expand Up @@ -12754,7 +12754,7 @@ Expression *OrOrExp::semantic(Scope *sc)
e1 = e1->checkToBoolean(sc);
unsigned cs1 = sc->callSuper;

if (sc->flags & SCOPEstaticif)
if (sc->flags & SCOPEcondition)
{
/* If in static if, don't evaluate e2 if we don't have to.
*/
Expand Down Expand Up @@ -12812,7 +12812,7 @@ Expression *AndAndExp::semantic(Scope *sc)
e1 = e1->checkToBoolean(sc);
unsigned cs1 = sc->callSuper;

if (sc->flags & SCOPEstaticif)
if (sc->flags & SCOPEcondition)
{
/* If in static if, don't evaluate e2 if we don't have to.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/func.c
Expand Up @@ -3386,7 +3386,7 @@ int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd)

Lerr:
// Don't give error if in template constraint
if (!(sc->flags & SCOPEstaticif))
if (!(sc->flags & SCOPEconstraint))
{
const char *xstatic = isStatic() ? "static " : "";
// better diagnostics for static functions
Expand Down
1 change: 0 additions & 1 deletion src/mtype.c
Expand Up @@ -6844,7 +6844,6 @@ void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol
*/
Scope *sc2 = sc->push();
sc2->intypeof = 1;
sc2->flags |= sc->flags & SCOPEstaticif;
exp = exp->semantic(sc2);
exp = resolvePropertiesOnly(sc2, exp);
sc2->pop();
Expand Down
2 changes: 1 addition & 1 deletion src/scope.c
Expand Up @@ -150,7 +150,7 @@ Scope *Scope::push()
s->slabel = NULL;
s->nofree = 0;
s->fieldinit = saveFieldInit();
s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile));
s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint));
s->lastdc = NULL;
s->lastoffset = 0;

Expand Down
16 changes: 9 additions & 7 deletions src/scope.h
Expand Up @@ -49,20 +49,22 @@ enum LINK;
#define CSXreturn 0x20 // seen a return statement
#define CSXany_ctor 0x40 // either this() or super() was called

// Flags that would not be inherited beyond scope nesting
#define SCOPEctor 0x0001 // constructor type
#define SCOPEstaticif 0x0002 // inside static if
#define SCOPEfree 0x0004 // is on free list
#define SCOPEstaticassert 0x0008 // inside static assert
#define SCOPEdebug 0x0010 // inside debug conditional
#define SCOPEnoaccesscheck 0x0002 // don't do access checks
#define SCOPEcondition 0x0004 // inside static if/assert condition
#define SCOPEdebug 0x0008 // inside debug conditional

// Flags that would be inherited beyond scope nesting
#define SCOPEconstraint 0x0010 // inside template constraint
#define SCOPEinvariant 0x0020 // inside invariant code
#define SCOPErequire 0x0040 // inside in contract code
#define SCOPEensure 0x0060 // inside out contract code
#define SCOPEcontract 0x0060 // [mask] we're inside contract code

#define SCOPEctfe 0x0080 // inside a ctfe-only expression
#define SCOPEnoaccesscheck 0x0100 // don't do access checks
#define SCOPEcompile 0x0200 // inside __traits(compile)
#define SCOPEcompile 0x0100 // inside __traits(compile)

#define SCOPEfree 0x8000 // is on free list

struct Scope
{
Expand Down
2 changes: 1 addition & 1 deletion src/staticassert.c
Expand Up @@ -53,7 +53,7 @@ void StaticAssert::semantic2(Scope *sc)
ScopeDsymbol *sds = new ScopeDsymbol();
sc = sc->push(sds);
sc->speculative = true;
sc->flags |= SCOPEstaticassert;
sc->flags |= SCOPEcondition;

sc = sc->startCTFE();
Expression *e = exp->semantic(sc);
Expand Down
8 changes: 4 additions & 4 deletions src/template.c
Expand Up @@ -781,7 +781,7 @@ bool TemplateDeclaration::evaluateConstraint(
Expression *e = constraint->syntaxCopy();

scx = scx->startCTFE();
scx->flags |= SCOPEstaticif;
scx->flags |= SCOPEcondition | SCOPEconstraint;
assert(ti->inst == NULL);
ti->inst = ti; // temporary instantiation to enable genIdent()

Expand Down Expand Up @@ -2501,7 +2501,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,

if (FuncLiteralDeclaration *fld = m->lastf->isFuncLiteralDeclaration())
{
if ((sc->flags & SCOPEstaticif) || sc->intypeof)
if ((sc->flags & SCOPEconstraint) || sc->intypeof)
{
// Inside template constraint, or inside typeof,
// nested reference check doesn't work correctly.
Expand Down Expand Up @@ -5863,7 +5863,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
//printf("\tspeculative ti %s '%s' gag = %d, spec = %d\n", tempdecl->parent->toChars(), toChars(), global.gag, sc->speculative);
speculative = true;
}
if (sc->flags & (SCOPEstaticif | SCOPEstaticassert | SCOPEcompile))
if (sc->flags & (SCOPEcondition | SCOPEcompile))
{
// Disconnect the chain if this instantiation is in definitely speculative context.
// It should be done after sc->instantiatingModule().
Expand Down Expand Up @@ -5947,7 +5947,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)

// If the first instantiation was in speculative context, but this is not:
if (!inst->tinst && inst->speculative &&
tinst && !(sc->flags & (SCOPEstaticif | SCOPEstaticassert | SCOPEcompile)))
tinst && !(sc->flags & (SCOPEcondition | SCOPEcompile)))
{
// Reconnect the chain if this instantiation is not in speculative context.
TemplateInstance *tix = tinst;
Expand Down
2 changes: 1 addition & 1 deletion src/traits.c
Expand Up @@ -909,7 +909,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc)
unsigned errors = global.startGagging();
Scope *sc2 = sc->push();
sc2->speculative = true;
sc2->flags = (sc->flags & ~SCOPEctfe) | SCOPEcompile;
sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile;
bool err = false;

RootObject *o = (*e->args)[i];
Expand Down
24 changes: 24 additions & 0 deletions test/compilable/compile1.d
Expand Up @@ -551,6 +551,30 @@ class C10326
invariant() { assert(val == 0); }
}

/***************************************************/
// 11042

static if ((true || error) == true ) {} else { static assert(0); }
static if ((false && error) == false) {} else { static assert(0); }
static assert ((true || error) == true );
static assert ((false && error) == false);
int f11042a1()() if ((true || error) == true ) { return 0; } enum x11042a1 = f11042a1();
int f11042b1()() if ((false && error) == false) { return 0; } enum x11042b1 = f11042b1();

static if (is(typeof(true || error)) == false) {} else { static assert(0); }
static if (is(typeof(false && error)) == false) {} else { static assert(0); }
static assert (is(typeof(true || error)) == false);
static assert (is(typeof(false && error)) == false);
int f11042a2()() if (is(typeof(true || error)) == false) { return 0; } enum x11042a2 = f11042a2();
int f11042b2()() if (is(typeof(false && error)) == false) { return 0; } enum x11042b2 = f11042b2();

static if (__traits(compiles, true || error) == false) {} else { static assert(0); }
static if (__traits(compiles, false && error) == false) {} else { static assert(0); }
static assert (__traits(compiles, true || error) == false);
static assert (__traits(compiles, false && error) == false);
int f11042a3()() if (__traits(compiles, true || error) == false) { return 0; } enum x11042a3 = f11042a3();
int f11042b3()() if (__traits(compiles, false && error) == false) { return 0; } enum x11042b3 = f11042b3();

/***************************************************/
// 11554

Expand Down
9 changes: 9 additions & 0 deletions test/fail_compilation/fail11042.d
@@ -0,0 +1,9 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail11042.d(8): Error: undefined identifier error, did you mean class Error?
fail_compilation/fail11042.d(9): Error: undefined identifier error, did you mean class Error?
---
*/
static if ({ return true || error; }()) {} // NG
static if ({ return false && error; }()) {} // NG
5 changes: 3 additions & 2 deletions test/fail_compilation/ice10949.d
@@ -1,8 +1,9 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice10949.d(9): Error: array index 3 is out of bounds [5, 5][0 .. 2]
fail_compilation/ice10949.d(9): Error: array index 17 is out of bounds [2, 3][0 .. 2]
fail_compilation/ice10949.d(10): Error: array index 3 is out of bounds [5, 5][0 .. 2]
fail_compilation/ice10949.d(10): Error: array index 17 is out of bounds [2, 3][0 .. 2]
fail_compilation/ice10949.d(10): Error: array index 9 is out of bounds [3, 3, 3][0 .. 3]
---
*/
int global;
Expand Down

0 comments on commit 2968596

Please sign in to comment.