Skip to content

Commit

Permalink
Issue 11169 - __traits(isAbstractClass) prematurely sets a class to b…
Browse files Browse the repository at this point in the history
…e abstract
  • Loading branch information
ibuclaw committed Jul 23, 2017
1 parent 5a9b3d2 commit 37c1edd
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 12 deletions.
9 changes: 8 additions & 1 deletion src/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ enum StructPOD
ISPODfwd, // POD not yet computed
};

enum Abstract
{
ABSfwdref = 0, // whether an abstract class is not yet computed
ABSyes, // is abstract class
ABSno, // is not abstract class
};

FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc);
FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc);
bool needOpEquals(StructDeclaration *sd);
Expand Down Expand Up @@ -272,7 +279,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
Abstract 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
50 changes: 43 additions & 7 deletions src/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla
com = false;
cpp = false;
isscope = false;
isabstract = false;
isabstract = ABSfwdref;
inuse = 0;
baseok = BASEOKnone;
objc.objc = false;
Expand Down Expand Up @@ -316,7 +316,7 @@ void ClassDeclaration::semantic(Scope *sc)
if (storage_class & STCscope)
isscope = true;
if (storage_class & STCabstract)
isabstract = true;
isabstract = ABSyes;

userAttribDecl = sc->userAttribDecl;

Expand Down Expand Up @@ -1263,19 +1263,55 @@ bool ClassDeclaration::isCPPinterface() const

bool ClassDeclaration::isAbstract()
{
if (isabstract)
return true;
if (isabstract != ABSfwdref)
return isabstract == ABSyes;

/* Bugzilla 11169: Resolve forward references to all class member functions,
* and determine whether this class is abstract.
*/
struct SearchAbstract
{
static int fp(Dsymbol *s, void* param)
{
FuncDeclaration *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++)
{
Dsymbol *s = (*members)[i];
if (s->apply(&SearchAbstract::fp, this))
{
isabstract = ABSyes;
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);
//if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd->loc.toChars(), fd->toChars());
if (!fd || fd->isAbstract())
{
isabstract = true;
isabstract = ABSyes;
return true;
}
}

isabstract = ABSno;
return false;
}

Expand Down
11 changes: 11 additions & 0 deletions src/dsymbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,17 @@ bool Dsymbol::needThis()
return false;
}

/*********************************
* Iterate this dsymbol or members of this scoped dsymbol, then
* call `fp` with the found symbol and `param`.
* Params:
* fp = function pointer to process the iterated symbol.
* If it returns nonzero, the iteration will be aborted.
* param = a parameter passed to fp.
* Returns:
* nonzero if the iteration is aborted by the return value of fp,
* or 0 if it's completed.
*/
int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param)
{
return (*fp)(this, param);
Expand Down
8 changes: 4 additions & 4 deletions src/func.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,15 +383,15 @@ void FuncDeclaration::semantic(Scope *sc)
assert(semanticRun <= PASSsemantic);
semanticRun = PASSsemantic;

parent = sc->parent;
Dsymbol *parent = toParent();

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

parent = sc->parent;
Dsymbol *parent = toParent();

unsigned dprogress_save = Module::dprogress;

foverrides.setDim(0); // reset in case semantic() is being retried for this function
Expand Down Expand Up @@ -714,7 +714,7 @@ void FuncDeclaration::semantic(Scope *sc)
}

if (storage_class & STCabstract)
cd->isabstract = true;
cd->isabstract = ABSyes;

// if static function, do not put in vtbl[]
if (!isVirtual())
Expand Down
2 changes: 2 additions & 0 deletions src/template.c
Original file line number Diff line number Diff line change
Expand Up @@ -8504,6 +8504,8 @@ bool TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident)

int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param)
{
if (_scope) // if fwd reference
semantic(NULL); // try to resolve it
if (members)
{
for (size_t i = 0; i < members->dim; i++)
Expand Down

0 comments on commit 37c1edd

Please sign in to comment.