Skip to content

Commit

Permalink
mv findVtblIndex() and overrideInterface() to funcsem.d (#16127)
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright authored Feb 2, 2024
1 parent 1c2ec41 commit da20db5
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 155 deletions.
3 changes: 2 additions & 1 deletion compiler/src/dmd/cppmanglewin.d
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
Expand Down Expand Up @@ -513,7 +514,7 @@ extern(D):
// 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",
//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");
}
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dmd/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,6 @@ class FuncDeclaration : public Declaration
Expressions *fdensureParams(Expressions *fdep);
bool equals(const RootObject * const o) const override final;

int findVtblIndex(Dsymbols *vtbl, int dim);
bool overloadInsert(Dsymbol *s) override;
bool inUnittest();
static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names);
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -6290,7 +6290,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto ad2 = b.sym;
ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
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);
exp.f = ad2.vtbl[vi].isFuncDeclaration();
assert(exp.f);
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -3793,7 +3793,6 @@ class FuncDeclaration : public Declaration
Array<Expression* >* fdensureParams(Array<Expression* >* param);
FuncDeclaration* syntaxCopy(Dsymbol* s) 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 inUnittest();
static MATCH leastAsSpecialized(FuncDeclaration* f, FuncDeclaration* g, Array<Identifier* >* names);
Expand Down
148 changes: 0 additions & 148 deletions compiler/src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -531,154 +531,6 @@ extern (C++) class FuncDeclaration : Declaration
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.
* Return true if successful; i.e. no conflict.
Expand Down
156 changes: 153 additions & 3 deletions compiler/src/dmd/funcsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
/* Find index of existing function in base class's vtbl[] to override
* (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;
switch (vi)
Expand Down Expand Up @@ -539,7 +539,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
/* if overriding an interface function, then this is not
* introducing and don't put it in the class vtbl[]
*/
funcdecl.interfaceVirtual = funcdecl.overrideInterface();
funcdecl.interfaceVirtual = overrideInterface(funcdecl);
if (funcdecl.interfaceVirtual)
{
//printf("\tinterface function %s\n", toChars());
Expand Down Expand Up @@ -764,7 +764,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
{
foreach (b; bcd.interfaces)
{
vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length);
vi = findVtblIndex(funcdecl, b.sym.vtbl[]);
switch (vi)
{
case -1:
Expand Down Expand Up @@ -1217,3 +1217,153 @@ extern (D) bool checkForwardRef(FuncDeclaration fd, const ref Loc loc)
}
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;
}

0 comments on commit da20db5

Please sign in to comment.