Skip to content

Commit

Permalink
fix Issue 11169 - __traits(isAbstractClass) prematurely sets a class …
Browse files Browse the repository at this point in the history
…to be abstract

__traits(isAbstractClass) should resolve forward references of all class member functions, in order to return stable result.
  • Loading branch information
9rnsr committed Apr 23, 2016
1 parent 5ca1a55 commit 1b46a1b
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/aggregate.h
Expand Up @@ -273,7 +273,7 @@ class ClassDeclaration : public AggregateDeclaration
bool com; // true if this is a COM class (meaning it derives from IUnknown)
bool cpp; // true if this is a C++ interface
bool isscope; // true if this is a scope class
bool isabstract; // true if abstract class
int isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract
int inuse; // to prevent recursive attempts
Baseok baseok; // set the progress of base classes resolving
Objc_ClassDeclaration objc;
Expand Down
48 changes: 41 additions & 7 deletions src/dclass.d
Expand Up @@ -212,7 +212,7 @@ public:
bool com; // true if this is a COM class (meaning it derives from IUnknown)
bool cpp; // true if this is a C++ interface
bool isscope; // true if this is a scope class
bool isabstract; // true if abstract class
int isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract
int inuse; // to prevent recursive attempts
Baseok baseok; // set the progress of base classes resolving

Expand Down Expand Up @@ -464,7 +464,7 @@ public:
if (storage_class & STCscope)
isscope = true;
if (storage_class & STCabstract)
isabstract = true;
isabstract = 1;

userAttribDecl = sc.userAttribDecl;

Expand Down Expand Up @@ -1415,18 +1415,52 @@ public:
*/
final bool isAbstract()
{
if (isabstract)
return true;
if (isabstract != 0)
return isabstract == 1;

/* Bugzilla 11169: Resolve forward references to all class member functions,
* and determine whether this class is abstract.
*/
extern (C++) static int func(Dsymbol s, void* param)
{
auto fd = s.isFuncDeclaration();
if (!fd)
return 0;
if (fd.storage_class & STCstatic)
return 0;

if (fd._scope)
fd.semantic(null);

if (fd.isAbstract())
return 1;
return 0;
}

for (size_t i = 0; i < members.dim; i++)
{
auto s = (*members)[i];
if (s.apply2(&func, cast(void*)this))
{
isabstract = 1;
return true;
}
}

/* Iterate inherited member functions and check their abstract attribute.
*/
for (size_t i = 1; i < vtbl.dim; i++)
{
FuncDeclaration fd = vtbl[i].isFuncDeclaration();
//printf("\tvtbl[%d] = %p\n", i, fd);
auto fd = vtbl[i].isFuncDeclaration();
//if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toChars());
if (!fd || fd.isAbstract())
{
isabstract = true;
isabstract = 1;
return true;
}
}

isabstract = 2;
return false;
}

Expand Down
8 changes: 4 additions & 4 deletions src/func.d
Expand Up @@ -553,15 +553,15 @@ public:
assert(semanticRun <= PASSsemantic);
semanticRun = PASSsemantic;

parent = sc.parent;
Dsymbol parent = toParent();

if (_scope)
{
sc = _scope;
_scope = null;
}

parent = sc.parent;
Dsymbol parent = toParent();

foverrides.setDim(0); // reset in case semantic() is being retried for this function

storage_class |= sc.stc & ~STCref;
Expand Down Expand Up @@ -849,7 +849,7 @@ public:
goto Ldone;
}
if (storage_class & STCabstract)
cd.isabstract = true;
cd.isabstract = 1;
// if static function, do not put in vtbl[]
if (!isVirtual())
{
Expand Down
45 changes: 45 additions & 0 deletions test/compilable/test11169.d
@@ -0,0 +1,45 @@
// REQUIRED_ARGS: -o-
/*
TEST_OUTPUT:
---
1: false
2: true
3: true
---
*/

class A
{
abstract void foo();
}

template MixinAbstractBar() { abstract void bar(); }

class B1 : A
{
// Use pragma instead of static assert, in order to evaluate
// __traits during ClassDeclaration.semantic().
pragma(msg, "1: ", __traits(isAbstractClass, typeof(this)));
override void foo() {}
}

class B2 : A
{
pragma(msg, "2: ", __traits(isAbstractClass, typeof(this)));
override void foo() {}
abstract void bar();
}

class B3 : A
{
pragma(msg, "3: ", __traits(isAbstractClass, typeof(this)));
override void foo() {}
mixin MixinAbstractBar!();
}

void main()
{
static assert( __traits(compiles, { auto b = new B1(); }));
static assert(!__traits(compiles, { auto b = new B2(); }));
static assert(!__traits(compiles, { auto b = new B3(); }));
}
28 changes: 28 additions & 0 deletions test/fail_compilation/fail11169.d
@@ -0,0 +1,28 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail11169.d(16): Error: error evaluating static if expression
---
*/

class A
{
abstract void foo();
}

class B : A
{
// __traits(isAbstractClass) is not usable in static if condition.
static if (__traits(isAbstractClass, typeof(this)))
{
}

override void foo()
{
}
}

void main()
{
B b = new B();
}

0 comments on commit 1b46a1b

Please sign in to comment.