mv findVtblIndex() and overrideInterface() to funcsem.d (#16127)

This commit is contained in:
Walter Bright 2024-02-02 07:26:59 -08:00 committed by GitHub
parent 1c2ec4194e
commit da20db5e0e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 156 additions and 155 deletions

View file

@ -25,6 +25,7 @@ import dmd.dtemplate;
import dmd.errors; import dmd.errors;
import dmd.expression; import dmd.expression;
import dmd.func; import dmd.func;
import dmd.funcsem;
import dmd.globals; import dmd.globals;
import dmd.id; import dmd.id;
import dmd.identifier; import dmd.identifier;
@ -513,7 +514,7 @@ extern(D):
// Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++
//printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n",
//d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual);
if ((d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) || (d.isDtorDeclaration() && d.parent.isClassDeclaration() && !d.isFinal())) if ((d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || overrideInterface(d))) || (d.isDtorDeclaration() && d.parent.isClassDeclaration() && !d.isFinal()))
{ {
mangleVisibility(buf, d, "EMU"); mangleVisibility(buf, d, "EMU");
} }

View file

@ -703,7 +703,6 @@ public:
Expressions *fdensureParams(Expressions *fdep); Expressions *fdensureParams(Expressions *fdep);
bool equals(const RootObject * const o) const override final; bool equals(const RootObject * const o) const override final;
int findVtblIndex(Dsymbols *vtbl, int dim);
bool overloadInsert(Dsymbol *s) override; bool overloadInsert(Dsymbol *s) override;
bool inUnittest(); bool inUnittest();
static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names);

View file

@ -6290,7 +6290,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto ad2 = b.sym; auto ad2 = b.sym;
ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
ue.e1 = ue.e1.expressionSemantic(sc); ue.e1 = ue.e1.expressionSemantic(sc);
auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length); auto vi = findVtblIndex(exp.f, ad2.vtbl[]);
assert(vi >= 0); assert(vi >= 0);
exp.f = ad2.vtbl[vi].isFuncDeclaration(); exp.f = ad2.vtbl[vi].isFuncDeclaration();
assert(exp.f); assert(exp.f);

View file

@ -3793,7 +3793,6 @@ public:
Array<Expression* >* fdensureParams(Array<Expression* >* param); Array<Expression* >* fdensureParams(Array<Expression* >* param);
FuncDeclaration* syntaxCopy(Dsymbol* s) override; FuncDeclaration* syntaxCopy(Dsymbol* s) override;
bool equals(const RootObject* const o) const final override; bool equals(const RootObject* const o) const final override;
int32_t findVtblIndex(Array<Dsymbol* >* vtbl, int32_t dim);
bool overloadInsert(Dsymbol* s) override; bool overloadInsert(Dsymbol* s) override;
bool inUnittest(); bool inUnittest();
static MATCH leastAsSpecialized(FuncDeclaration* f, FuncDeclaration* g, Array<Identifier* >* names); static MATCH leastAsSpecialized(FuncDeclaration* f, FuncDeclaration* g, Array<Identifier* >* names);

View file

@ -531,154 +531,6 @@ extern (C++) class FuncDeclaration : Declaration
return result; return result;
} }
/*************************************************
* Find index of function in vtbl[0..length] that
* this function overrides.
* Prefer an exact match to a covariant one.
* Params:
* vtbl = vtable to use
* dim = maximal vtable dimension
* Returns:
* -1 didn't find one
* -2 can't determine because of forward references
*/
final int findVtblIndex(Dsymbols* vtbl, int dim)
{
//printf("findVtblIndex() %s\n", toChars());
import dmd.typesem : covariant;
FuncDeclaration mismatch = null;
StorageClass mismatchstc = 0;
int mismatchvi = -1;
int exactvi = -1;
int bestvi = -1;
for (int vi = 0; vi < dim; vi++)
{
FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
if (fdv && fdv.ident == ident)
{
if (type.equals(fdv.type)) // if exact match
{
if (fdv.parent.isClassDeclaration())
{
if (fdv.isFuture())
{
bestvi = vi;
continue; // keep looking
}
return vi; // no need to look further
}
if (exactvi >= 0)
{
.error(loc, "%s `%s` cannot determine overridden function", kind, toPrettyChars);
return exactvi;
}
exactvi = vi;
bestvi = vi;
continue;
}
StorageClass stc = 0;
const cov = type.covariant(fdv.type, &stc);
//printf("\tbaseclass cov = %d\n", cov);
final switch (cov)
{
case Covariant.distinct:
// types are distinct
break;
case Covariant.yes:
bestvi = vi; // covariant, but not identical
break;
// keep looking for an exact match
case Covariant.no:
mismatchvi = vi;
mismatchstc = stc;
mismatch = fdv; // overrides, but is not covariant
break;
// keep looking for an exact match
case Covariant.fwdref:
return -2; // forward references
}
}
}
if (_linkage == LINK.cpp && bestvi != -1)
{
StorageClass stc = 0;
FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration();
assert(fdv && fdv.ident == ident);
if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
{
/* https://issues.dlang.org/show_bug.cgi?id=22351
* Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
* For now, continue to allow D covariant rules to apply when `override` has been used,
* but issue a deprecation warning that this behaviour will change in the future.
* Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
*/
if (isOverride())
{
/* @@@DEPRECATED_2.110@@@
* After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
* but also the `cppCovariant` parameter from Type.covariant, and update the function
* so that both `LINK.cpp` covariant conditions within are always checked.
*/
.deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars());
const char* where = type.isNaked() ? "parameters" : "type";
deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the "
~ "overriding function %s", where);
}
else
{
// Treat as if Covariant.no
mismatchvi = bestvi;
mismatchstc = stc;
mismatch = fdv;
bestvi = -1;
}
}
}
if (bestvi == -1 && mismatch)
{
//type.print();
//mismatch.type.print();
//printf("%s %s\n", type.deco, mismatch.type.deco);
//printf("stc = %llx\n", mismatchstc);
if (mismatchstc)
{
// Fix it by modifying the type to add the storage classes
type = type.addStorageClass(mismatchstc);
bestvi = mismatchvi;
}
}
return bestvi;
}
/*********************************
* If function a function in a base class,
* return that base class.
* Returns:
* base class if overriding, null if not
*/
extern (D) final BaseClass* overrideInterface()
{
for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
{
foreach (b; cd.interfaces)
{
auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length);
if (v >= 0)
return b;
}
}
return null;
}
/**************************************************** /****************************************************
* Overload this FuncDeclaration with the new one f. * Overload this FuncDeclaration with the new one f.
* Return true if successful; i.e. no conflict. * Return true if successful; i.e. no conflict.

View file

@ -502,7 +502,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
/* Find index of existing function in base class's vtbl[] to override /* Find index of existing function in base class's vtbl[] to override
* (the index will be the same as in cd's current vtbl[]) * (the index will be the same as in cd's current vtbl[])
*/ */
int vi = cd.baseClass ? funcdecl.findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.length) : -1; int vi = cd.baseClass ? findVtblIndex(funcdecl, cd.baseClass.vtbl[]) : -1;
bool doesoverride = false; bool doesoverride = false;
switch (vi) switch (vi)
@ -539,7 +539,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
/* if overriding an interface function, then this is not /* if overriding an interface function, then this is not
* introducing and don't put it in the class vtbl[] * introducing and don't put it in the class vtbl[]
*/ */
funcdecl.interfaceVirtual = funcdecl.overrideInterface(); funcdecl.interfaceVirtual = overrideInterface(funcdecl);
if (funcdecl.interfaceVirtual) if (funcdecl.interfaceVirtual)
{ {
//printf("\tinterface function %s\n", toChars()); //printf("\tinterface function %s\n", toChars());
@ -764,7 +764,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
{ {
foreach (b; bcd.interfaces) foreach (b; bcd.interfaces)
{ {
vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length); vi = findVtblIndex(funcdecl, b.sym.vtbl[]);
switch (vi) switch (vi)
{ {
case -1: case -1:
@ -1217,3 +1217,153 @@ extern (D) bool checkForwardRef(FuncDeclaration fd, const ref Loc loc)
} }
return false; return false;
} }
/*************************************************
* Find index of function in vtbl[0..length] that
* this function overrides.
* Prefer an exact match to a covariant one.
* Params:
* fd = function
* vtbl = vtable to use
* Returns:
* -1 didn't find one
* -2 can't determine because of forward references
*/
int findVtblIndex(FuncDeclaration fd, Dsymbol[] vtbl)
{
//printf("findVtblIndex() %s\n", toChars());
import dmd.typesem : covariant;
FuncDeclaration mismatch = null;
StorageClass mismatchstc = 0;
int mismatchvi = -1;
int exactvi = -1;
int bestvi = -1;
for (int vi = 0; vi < cast(int)vtbl.length; vi++)
{
FuncDeclaration fdv = vtbl[vi].isFuncDeclaration();
if (fdv && fdv.ident == fd.ident)
{
if (fd.type.equals(fdv.type)) // if exact match
{
if (fdv.parent.isClassDeclaration())
{
if (fdv.isFuture())
{
bestvi = vi;
continue; // keep looking
}
return vi; // no need to look further
}
if (exactvi >= 0)
{
.error(fd.loc, "%s `%s` cannot determine overridden function", fd.kind, fd.toPrettyChars);
return exactvi;
}
exactvi = vi;
bestvi = vi;
continue;
}
StorageClass stc = 0;
const cov = fd.type.covariant(fdv.type, &stc);
//printf("\tbaseclass cov = %d\n", cov);
final switch (cov)
{
case Covariant.distinct:
// types are distinct
break;
case Covariant.yes:
bestvi = vi; // covariant, but not identical
break;
// keep looking for an exact match
case Covariant.no:
mismatchvi = vi;
mismatchstc = stc;
mismatch = fdv; // overrides, but is not covariant
break;
// keep looking for an exact match
case Covariant.fwdref:
return -2; // forward references
}
}
}
if (fd._linkage == LINK.cpp && bestvi != -1)
{
StorageClass stc = 0;
FuncDeclaration fdv = vtbl[bestvi].isFuncDeclaration();
assert(fdv && fdv.ident == fd.ident);
if (fd.type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
{
/* https://issues.dlang.org/show_bug.cgi?id=22351
* Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
* For now, continue to allow D covariant rules to apply when `override` has been used,
* but issue a deprecation warning that this behaviour will change in the future.
* Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
*/
if (fd.isOverride())
{
/* @@@DEPRECATED_2.110@@@
* After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
* but also the `cppCovariant` parameter from Type.covariant, and update the function
* so that both `LINK.cpp` covariant conditions within are always checked.
*/
.deprecation(fd.loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
fd.toPrettyChars(), fd.type.toTypeFunction().parameterList.parametersTypeToChars(), fd.type.modToChars());
const char* where = fd.type.isNaked() ? "parameters" : "type";
deprecationSupplemental(fd.loc, "Either remove `override`, or adjust the `const` qualifiers of the "
~ "overriding function %s", where);
}
else
{
// Treat as if Covariant.no
mismatchvi = bestvi;
mismatchstc = stc;
mismatch = fdv;
bestvi = -1;
}
}
}
if (bestvi == -1 && mismatch)
{
//type.print();
//mismatch.type.print();
//printf("%s %s\n", type.deco, mismatch.type.deco);
//printf("stc = %llx\n", mismatchstc);
if (mismatchstc)
{
// Fix it by modifying the type to add the storage classes
fd.type = fd.type.addStorageClass(mismatchstc);
bestvi = mismatchvi;
}
}
return bestvi;
}
/*********************************
* If function is a function in a base class,
* return that base class.
* Params:
* fd = function
* Returns:
* base class if overriding, null if not
*/
BaseClass* overrideInterface(FuncDeclaration fd)
{
for (ClassDeclaration cd = fd.toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
{
foreach (b; cd.interfaces)
{
auto v = findVtblIndex(fd, b.sym.vtbl[]);
if (v >= 0)
return b;
}
}
return null;
}