Skip to content

Commit

Permalink
fix Issue 14093 - __traits(compiles, cast(Object)(tuple)) is true eve…
Browse files Browse the repository at this point in the history
…n if it doesn't compile.

Move invalid cast check into Expression::castTo().
  • Loading branch information
9rnsr committed Feb 10, 2015
1 parent 447039d commit 1d0268e
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 50 deletions.
58 changes: 57 additions & 1 deletion src/cast.c
Expand Up @@ -1475,9 +1475,54 @@ Expression *castTo(Expression *e, Scope *sc, Type *t)
result->type = t;
return;
}

// Bugzlla 3133: Struct casts are possible only when the sizes match
// Same with static array -> static array
if ((t1b->ty == Tsarray || t1b->ty == Tstruct) &&
(tob->ty == Tsarray || tob->ty == Tstruct))
{
if (t1b->size(e->loc) != tob->size(e->loc))
goto Lfail;
}
// Bugzilla 9178: Tsarray <--> typeof(null)
// Bugzilla 9904: Tstruct <--> typeof(null)
if (t1b->ty == Tnull && (tob->ty == Tsarray || tob->ty == Tstruct) ||
tob->ty == Tnull && (t1b->ty == Tsarray || t1b->ty == Tstruct))
{
goto Lfail;
}
// Bugzilla 13959: Tstruct <--> Tpointer
if ((tob->ty == Tstruct && t1b->ty == Tpointer) ||
(t1b->ty == Tstruct && tob->ty == Tpointer))
{
goto Lfail;
}
// Bugzilla 10646: Tclass <--> (T[] or T[n])
if (tob->ty == Tclass && (t1b->ty == Tarray || t1b->ty == Tsarray) ||
t1b->ty == Tclass && (tob->ty == Tarray || tob->ty == Tsarray))
{
goto Lfail;
}
// Bugzilla 11484: (T[] or T[n]) <--> TypeBasic
// Bugzilla 11485, 7472: Tclass <--> TypeBasic
// Bugzilla 14154L Tstruct <--> TypeBasic
if (t1b->isTypeBasic() && (tob->ty == Tarray || tob->ty == Tsarray || tob->ty == Tclass || tob->ty == Tstruct) ||
tob->isTypeBasic() && (t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Tclass || t1b->ty == Tstruct))
{
goto Lfail;
}
if (t1b->ty == Tvoid && tob->ty != Tvoid && e->op != TOKfunction)
{
Lfail:
e->error("cannot cast expression %s of type %s to %s",
e->toChars(), e->type->toChars(), t->toChars());
result = new ErrorExp();
return;
}

L1:
result = new CastExp(e->loc, e, tob);
result->type = t;
result->type = t; // Don't call semantic()
//printf("Returning: %s\n", result->toChars());
}

Expand Down Expand Up @@ -1898,6 +1943,17 @@ Expression *castTo(Expression *e, Scope *sc, Type *t)
(*te->exps)[i] = ex;
}
result = te;

/* Questionable behavior: In here, result->type is not set to t.
* Therefoe:
* TypeTuple!(int, int) values;
* auto values2 = cast(long)values;
* // typeof(values2) == TypeTuple!(int, int) !!
*
* Only when the casted tuple is immediately expanded, it would work.
* auto arr = [cast(long)values];
* // typeof(arr) == long[]
*/
}

void visit(ArrayLiteralExp *e)
Expand Down
52 changes: 4 additions & 48 deletions src/expression.c
Expand Up @@ -9611,50 +9611,10 @@ Expression *CastExp::semantic(Scope *sc)
if (tob->ty == Tpointer && t1b->ty == Tdelegate)
deprecation("casting from %s to %s is deprecated", e1->type->toChars(), to->toChars());

{
// Bugzlla 3133: Struct casts are possible only when the sizes match
// Same with static array -> static array
if ((t1b->ty == Tsarray || t1b->ty == Tstruct) &&
(tob->ty == Tsarray || tob->ty == Tstruct))
{
if (t1b->size(loc) != tob->size(loc))
goto Lfail;
}

// Bugzilla 9178: Tsarray <--> typeof(null)
// Bugzilla 9904: Tstruct <--> typeof(null)
if (t1b->ty == Tnull && (tob->ty == Tsarray || tob->ty == Tstruct) ||
tob->ty == Tnull && (t1b->ty == Tsarray || t1b->ty == Tstruct))
{
goto Lfail;
}

// Bugzilla 13959: Tstruct <--> Tpointer
if ((tob->ty == Tstruct && t1b->ty == Tpointer) ||
(t1b->ty == Tstruct && tob->ty == Tpointer))
{
goto Lfail;
}

// Bugzilla 10646: Tclass <--> (T[] or T[n])
if (tob->ty == Tclass && (t1b->ty == Tarray || t1b->ty == Tsarray) ||
t1b->ty == Tclass && (tob->ty == Tarray || tob->ty == Tsarray))
{
goto Lfail;
}

// Bugzilla 11484: (T[] or T[n]) <--> TypeBasic
// Bugzilla 11485, 7472: Tclass <--> TypeBasic
// Bugzilla 14154L Tstruct <--> TypeBasic
if (t1b->isTypeBasic() && (tob->ty == Tarray || tob->ty == Tsarray || tob->ty == Tclass || tob->ty == Tstruct) ||
tob->isTypeBasic() && (t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Tclass || t1b->ty == Tstruct))
{
goto Lfail;
}

if (t1b->ty == Tvoid && tob->ty != Tvoid && e1->op != TOKfunction)
goto Lfail;
}
Expression *ex = e1->castTo(sc, to);
if (ex->op == TOKerror)
return ex;

// Check for unsafe casts
if (sc->func && !sc->intypeof)
Expand Down Expand Up @@ -9720,11 +9680,7 @@ Expression *CastExp::semantic(Scope *sc)
}

Lsafe:
return e1->castTo(sc, to);

Lfail:
error("cannot cast expression %s of type %s to %s", e1->toChars(), e1->type->toChars(), to->toChars());
return new ErrorExp();
return ex;
}

/************************************************************/
Expand Down
37 changes: 36 additions & 1 deletion test/fail_compilation/fail_casting.d
Expand Up @@ -133,7 +133,7 @@ void test13959()
/*
TEST_OUTPUT:
---
fail_compilation/fail_casting.d(144): Error: cannot cast expression mi of type MyInt14154 to MyUbyte14154
fail_compilation/fail_casting.d(144): Error: cannot cast expression mi.x of type int to MyUbyte14154
---
*/
struct MyUbyte14154 { ubyte x; alias x this; }
Expand All @@ -143,3 +143,38 @@ void test14154()
MyInt14154 mi;
ubyte t = cast(MyUbyte14154)mi;
}

/*
TEST_OUTPUT:
---
fail_compilation/fail_casting.d(179): Error: cannot cast expression __tup3.__expand_field_0 of type int to object.Object
fail_compilation/fail_casting.d(179): Error: cannot cast expression __tup3.__expand_field_1 of type int to object.Object
---
*/
alias TypeTuple14093(T...) = T;
struct Tuple14093(T...)
{
static if (T.length == 4)
{
alias Types = TypeTuple14093!(T[0], T[2]);

Types expand;

@property ref inout(Tuple14093!Types) _Tuple_super() inout @trusted
{
return *cast(typeof(return)*) &(expand[0]);
}
alias _Tuple_super this;
}
else
{
alias Types = T;
Types expand;
alias expand this;
}
}
void test14093()
{
Tuple14093!(int, "x", int, "y") point;
auto newPoint = cast(Object)(point);
}

0 comments on commit 1d0268e

Please sign in to comment.