diff --git a/src/aggregate.h b/src/aggregate.h index 16b5d15994d1..d90e4de42369 100644 --- a/src/aggregate.h +++ b/src/aggregate.h @@ -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; diff --git a/src/dclass.d b/src/dclass.d index f611ac96164d..32ff8cee9e4a 100644 --- a/src/dclass.d +++ b/src/dclass.d @@ -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 @@ -464,7 +464,7 @@ public: if (storage_class & STCscope) isscope = true; if (storage_class & STCabstract) - isabstract = true; + isabstract = 1; userAttribDecl = sc.userAttribDecl; @@ -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; } diff --git a/src/func.d b/src/func.d index e60c5b83e2e7..602441a6741b 100644 --- a/src/func.d +++ b/src/func.d @@ -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; @@ -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()) { diff --git a/test/compilable/test11169.d b/test/compilable/test11169.d new file mode 100644 index 000000000000..10a3df2c7a6e --- /dev/null +++ b/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(); })); +} diff --git a/test/fail_compilation/fail11169.d b/test/fail_compilation/fail11169.d new file mode 100644 index 000000000000..e6ab4a64886b --- /dev/null +++ b/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(); +}