Extracted ClassDeclaration.isAbstract to dsymbolsem (#21131)

This commit is contained in:
Matthew Qiu 2025-04-02 04:37:36 -04:00 committed by GitHub
parent d7dce783a7
commit 3106359a2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 111 additions and 107 deletions

View file

@ -293,7 +293,6 @@ public:
virtual bool isCOMinterface() const;
bool isCPPclass() const;
virtual bool isCPPinterface() const;
bool isAbstract();
virtual int vtblOffset() const;
const char *kind() const override;

View file

@ -192,6 +192,12 @@ Dsymbol vtblSymbol(ClassDeclaration cd)
return dmd.dsymbolsem.vtblSymbol(cd);
}
bool isAbstract(ClassDeclaration cd)
{
import dmd.dsymbolsem;
return dmd.dsymbolsem.isAbstract(cd);
}
/***********************************************************
* dtemplate.d
*/

View file

@ -23,7 +23,7 @@ import dmd.gluelayer;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem : dsymbolSemantic, addMember, setFieldOffset;
import dmd.dsymbolsem : setFieldOffset;
import dmd.errors;
import dmd.func;
import dmd.id;
@ -33,7 +33,6 @@ import dmd.mtype;
import dmd.objc;
import dmd.root.rmem;
import dmd.target;
import dmd.typesem : covariant, immutableOf, sarrayOf;
import dmd.visitor;
/***********************************************************
@ -757,106 +756,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
return false;
}
/****************************************
*/
final bool isAbstract()
{
enum log = false;
if (isabstract != ThreeState.none)
return isabstract == ThreeState.yes;
if (log) printf("isAbstract(%s)\n", toChars());
bool no() { if (log) printf("no\n"); isabstract = ThreeState.no; return false; }
bool yes() { if (log) printf("yes\n"); isabstract = ThreeState.yes; return true; }
if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_)
return yes();
if (errors)
return no();
/* https://issues.dlang.org/show_bug.cgi?id=11169
* Resolve forward references to all class member functions,
* and determine whether this class is abstract.
*/
static int func(Dsymbol s, void*)
{
auto fd = s.isFuncDeclaration();
if (!fd)
return 0;
if (fd.storage_class & STC.static_)
return 0;
if (fd.isAbstract())
return 1;
return 0;
}
// opaque class is not abstract if it is not declared abstract
if (!members)
return no();
for (size_t i = 0; i < members.length; i++)
{
auto s = (*members)[i];
if (s.apply(&func, null))
{
return yes();
}
}
/* If the base class is not abstract, then this class cannot
* be abstract.
*/
if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract()))
return no();
/* If any abstract functions are inherited, but not overridden,
* then the class is abstract. Do this by checking the vtbl[].
* Need to do semantic() on class to fill the vtbl[].
*/
this.dsymbolSemantic(null);
/* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
* is called recursively it can set PASS.semanticdone without finishing it.
*/
//if (semanticRun < PASS.semanticdone)
{
/* Could not complete semantic(). Try running semantic() on
* each of the virtual functions,
* which will fill in the vtbl[] overrides.
*/
static int virtualSemantic(Dsymbol s, void*)
{
auto fd = s.isFuncDeclaration();
if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
fd.dsymbolSemantic(null);
return 0;
}
for (size_t i = 0; i < members.length; i++)
{
auto s = (*members)[i];
s.apply(&virtualSemantic,null);
}
}
/* Finally, check the vtbl[]
*/
foreach (i; 1 .. vtbl.length)
{
auto fd = vtbl[i].isFuncDeclaration();
//if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
if (!fd || fd.isAbstract())
{
return yes();
}
}
return no();
}
/****************************************
* Determine if slot 0 of the vtbl[] is reserved for something else.
* For class objects, yes, this is where the classinfo ptr goes.

View file

@ -39,6 +39,7 @@ namespace dmd
PURE isPure(FuncDeclaration *f);
FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
bool isAbstract(ClassDeclaration *cd);
}
//enum STC : ulong from astenums.d:

View file

@ -8210,3 +8210,101 @@ Dsymbol vtblSymbol(ClassDeclaration cd)
}
return cd.vtblsym;
}
extern(C++) bool isAbstract(ClassDeclaration cd)
{
enum log = false;
if (cd.isabstract != ThreeState.none)
return cd.isabstract == ThreeState.yes;
if (log) printf("isAbstract(%s)\n", cd.toChars());
bool no() { if (log) printf("no\n"); cd.isabstract = ThreeState.no; return false; }
bool yes() { if (log) printf("yes\n"); cd.isabstract = ThreeState.yes; return true; }
if (cd.storage_class & STC.abstract_ || cd._scope && cd._scope.stc & STC.abstract_)
return yes();
if (cd.errors)
return no();
/* https://issues.dlang.org/show_bug.cgi?id=11169
* Resolve forward references to all class member functions,
* and determine whether this class is abstract.
*/
static int func(Dsymbol s, void*)
{
auto fd = s.isFuncDeclaration();
if (!fd)
return 0;
if (fd.storage_class & STC.static_)
return 0;
if (fd.isAbstract())
return 1;
return 0;
}
// opaque class is not abstract if it is not declared abstract
if (!(cd.members))
return no();
for (size_t i = 0; i < cd.members.length; i++)
{
auto s = (*(cd.members))[i];
if (s.apply(&func, null))
{
return yes();
}
}
/* If the base class is not abstract, then this class cannot
* be abstract.
*/
if (!cd.isInterfaceDeclaration() && (!cd.baseClass || !cd.baseClass.isAbstract()))
return no();
/* If any abstract functions are inherited, but not overridden,
* then the class is abstract. Do this by checking the vtbl[].
* Need to do semantic() on class to fill the vtbl[].
*/
cd.dsymbolSemantic(null);
/* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
* is called recursively it can set PASS.semanticdone without finishing it.
*/
//if (semanticRun < PASS.semanticdone)
{
/* Could not complete semantic(). Try running semantic() on
* each of the virtual functions,
* which will fill in the vtbl[] overrides.
*/
static int virtualSemantic(Dsymbol s, void*)
{
auto fd = s.isFuncDeclaration();
if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
fd.dsymbolSemantic(null);
return 0;
}
for (size_t i = 0; i < cd.members.length; i++)
{
auto s = (*(cd.members))[i];
s.apply(&virtualSemantic,null);
}
}
/* Finally, check the vtbl[]
*/
foreach (i; 1 .. cd.vtbl.length)
{
auto fd = cd.vtbl[i].isFuncDeclaration();
//if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
if (!fd || fd.isAbstract())
{
return yes();
}
}
return no();
}

View file

@ -6707,7 +6707,6 @@ public:
virtual bool isCOMinterface() const;
bool isCPPclass() const;
virtual bool isCPPinterface() const;
bool isAbstract();
virtual int32_t vtblOffset() const;
const char* kind() const override;
void addObjcSymbols(Array<ClassDeclaration* >* classes, Array<ClassDeclaration* >* categories) final override;
@ -7569,6 +7568,8 @@ extern bool hasStaticCtorOrDtor(Dsymbol* d);
extern bool isFuncHidden(ClassDeclaration* cd, FuncDeclaration* fd);
extern bool isAbstract(ClassDeclaration* cd);
extern void lowerNonArrayAggregate(StaticForeach* sfe, Scope* sc);
extern int32_t include(Condition* c, Scope* sc);

View file

@ -35,7 +35,7 @@ import dmd.dmodule;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
import dmd.dsymbolsem : hasStaticCtorOrDtor, include, isFuncHidden;
import dmd.dsymbolsem : hasStaticCtorOrDtor, include, isFuncHidden, isAbstract;
import dmd.dtemplate;
import dmd.errors;
import dmd.errorsink;

View file

@ -1325,7 +1325,7 @@ public:
for (size_t i = d->vtblOffset(); i < d->vtbl.length; i++)
{
FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration();
if (!fd || (!fd->fbody && d->isAbstract()))
if (!fd || (!fd->fbody && dmd::isAbstract(d)))
continue;
if (!dmd::functionSemantic(fd))
return;
@ -1403,7 +1403,7 @@ public:
for (size_t i = d->vtblOffset(); i < d->vtbl.length; i++)
{
FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration();
if (fd && (fd->fbody || !d->isAbstract()))
if (fd && (fd->fbody || !dmd::isAbstract(d)))
visitDeclaration(fd);
}
d->type->accept(this);