Skip to content

Commit

Permalink
fix Issue 17059 - incorrect circular reference with `is(Klass : Inter…
Browse files Browse the repository at this point in the history
…face)`

- fixed by tweaking the fix for Issue 16980 (#6383)
- happened b/c TypeClass::implicitConv -> TypeClass::constConv checks
  for offset == 0, which triggered size finalization
- instead handle unfinalized classes in isBaseOf (new OFFSET_FWDREF)
  and only explicity finalize size before optimizing casts
- add a halt for any OFFSET_FWDREF leaking through to IR gen
  • Loading branch information
MartinNowak committed Jan 8, 2017
1 parent d3187d6 commit c4ac1ab
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/aggregate.h
Expand Up @@ -288,6 +288,7 @@ class ClassDeclaration : public AggregateDeclaration
bool isBaseOf2(ClassDeclaration *cd);

#define OFFSET_RUNTIME 0x76543210
#define OFFSET_FWDREF 0x76543211
virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);

bool isBaseInfoComplete();
Expand Down
8 changes: 3 additions & 5 deletions src/dclass.d
Expand Up @@ -1027,6 +1027,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
}

enum OFFSET_RUNTIME = 0x76543210;
enum OFFSET_FWDREF = 0x76543211;

/*******************************************
* Determine if 'this' is a base class of cd.
Expand Down Expand Up @@ -1878,11 +1879,8 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration
{
if (poffset)
{
// Need to determine correct offset if needed.
// https://issues.dlang.org/show_bug.cgi?id=16980
cd.size(loc);
// HACK: using OFFSET_RUNTIME as error placeholder
*poffset = cd.sizeok == SIZEOKdone ? b.offset : OFFSET_RUNTIME;
// don't return incorrect offsets https://issues.dlang.org/show_bug.cgi?id=16980
*poffset = cd.sizeok == SIZEOKdone ? b.offset : OFFSET_FWDREF;
}
// printf("\tfound at offset %d\n", b.offset);
return true;
Expand Down
6 changes: 5 additions & 1 deletion src/e2ir.d
Expand Up @@ -4034,7 +4034,11 @@ elem *toElem(Expression e, IRState *irs)
*/

//printf("offset = %d\n", offset);
if (offset)
if (offset == ClassDeclaration.OFFSET_FWDREF)
{
assert(0, "unexpected forward reference");
}
else if (offset)
{
/* Rewrite cast as (e ? e + offset : null)
*/
Expand Down
7 changes: 7 additions & 0 deletions src/optimize.d
Expand Up @@ -589,9 +589,16 @@ extern (C++) Expression Expression_optimize(Expression e, int result, bool keepL
}
if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
{
import ddmd.aggregate : SIZEOKdone;

// See if we can remove an unnecessary cast
ClassDeclaration cdfrom = e.e1.type.isClassHandle();
ClassDeclaration cdto = e.type.isClassHandle();
// Need to determine correct offset before optimizing away the cast.
// https://issues.dlang.org/show_bug.cgi?id=16980
cdfrom.size(e.loc);
assert(cdfrom.sizeok == SIZEOKdone);
assert(cdto.sizeok == SIZEOKdone || !cdto.isBaseOf(cdto, null));
int offset;
if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
{
Expand Down
11 changes: 11 additions & 0 deletions test/compilable/test17059.d
@@ -0,0 +1,11 @@
mixin template impl()
{
alias T = typeof(this);
enum doImplement = is(T : I);

static if (doImplement)
{}
}

interface I {}
class A : I {mixin impl;}

0 comments on commit c4ac1ab

Please sign in to comment.