mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
mv findVtblIndex() and overrideInterface() to funcsem.d (#16127)
This commit is contained in:
parent
1c2ec4194e
commit
da20db5e0e
6 changed files with 156 additions and 155 deletions
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue