Skip to content

Commit

Permalink
allow new returns to be implicitly cast
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Nov 12, 2012
1 parent 6405908 commit 4b2767e
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/cast.c
Expand Up @@ -853,6 +853,122 @@ MATCH CastExp::implicitConvTo(Type *t)
return result;
}

MATCH NewExp::implicitConvTo(Type *t)
{
#if 0
printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH match = Expression::implicitConvTo(t);
if (match != MATCHnomatch)
return match;

/* The return from new() is special in that it might be a unique pointer.
* If we can prove it is, allow the following implicit conversions:
* mutable => immutable
* non-shared => shared
* shared => non-shared
*/

Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();

if (tb->ty == Tclass)
{
//printf("%s => %s\n", type->castMod(0)->toChars(), t->castMod(0)->toChars());
match = type->castMod(0)->implicitConvTo(t->castMod(0));
if (!match)
goto Lnomatch;

// Regardless, don't allow immutable to be implicitly converted to mutable
if (tb->isMutable() && !typeb->isMutable())
goto Lnomatch;

// All the fields must be convertible as well
ClassDeclaration *cd = ((TypeClass *)tb)->sym;

cd->size(loc); // resolve any forward references

/* The following is excessively conservative, but be very
* careful in loosening them up.
*/
if (cd->isNested() ||
cd->isInterfaceDeclaration() ||
cd->ctor ||
cd->baseClass != ClassDeclaration::object)
goto Lnomatch;

for (size_t i = 0; i < cd->fields.dim; i++)
{ Dsymbol *sm = cd->fields[i];
Declaration *d = sm->isDeclaration();
if (d->storage_class & STCref || d->hasPointers())
goto Lnomatch;
}
return (match == MATCHexact) ? MATCHconst : match;
}
else if ((tb->ty == Tpointer || tb->ty == Tarray) &&
(typeb->ty == Tpointer || typeb->ty == Tarray))
{
Type *typen = type->nextOf()->toBasetype();
Type *tn = tb->nextOf()->toBasetype();

//printf("%s => %s\n", typen->castMod(0)->toChars(), tn->castMod(0)->toChars());
{
/* Determine if the match failure was solely due to a difference
* in the mod bits, by rebuilding type and t without mod bits and
* retrying the implicit conversion.
*/
Type *tn2 = tn->castMod(0); // cast off mod bits
Type *typen2 = typen->castMod(0);
Type *t2 = (tb->ty == Tpointer) ? tn2->pointerTo() : tn2->arrayOf();
Type *type2 = (typeb->ty == Tpointer) ? typen2->pointerTo() : typen2->arrayOf();
match = type2->implicitConvTo(t2);
if (!match)
goto Lnomatch;
}

// Regardless, don't allow immutable to be implicitly converted to mutable
if (tn->isMutable() && !typen->isMutable())
goto Lnomatch;

if (tn->isTypeBasic())
;
else if (tn->ty == Tstruct)
{
// All the fields must be convertible as well
StructDeclaration *sd = ((TypeStruct *)tn)->sym;

sd->size(loc); // resolve any forward references

/* The following is excessively conservative, but be very
* careful in loosening them up.
*/

if (sd->isNested() ||
sd->ctor)
goto Lnomatch;

for (size_t i = 0; i < sd->fields.dim; i++)
{ Dsymbol *sm = sd->fields[i];
Declaration *d = sm->isDeclaration();
if (d->storage_class & STCref || d->hasPointers())
goto Lnomatch;
}
}
else
{
/* More fruit left on the table, such as pointers to immutable.
*/
goto Lnomatch;
}

return (match == MATCHexact) ? MATCHconst : match;
}

Lnomatch:
return MATCHnomatch;
}

/* ==================== castTo ====================== */

/**************************************
Expand Down
1 change: 1 addition & 0 deletions src/expression.h
Expand Up @@ -572,6 +572,7 @@ struct NewExp : Expression
Expression *semantic(Scope *sc);
Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
Expression *optimize(int result);
MATCH implicitConvTo(Type *t);
elem *toElem(IRState *irs);
void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

Expand Down
1 change: 1 addition & 0 deletions src/struct.c
Expand Up @@ -288,6 +288,7 @@ unsigned AggregateDeclaration::placeField(

int AggregateDeclaration::isNested()
{
assert((isnested & ~1) == 0);
return isnested;
}

Expand Down

0 comments on commit 4b2767e

Please sign in to comment.