mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-25 05:21:02 +00:00
- allow skipping optional arguments of the parent function in a virtual override definition.
This is mainly to allow retroactive addition to existing virtual functions without breaking existing content. The MeansOfDeath fix for Actor.Die would not be possible without such handling.
This commit is contained in:
parent
ff69d945e1
commit
6634416b89
3 changed files with 29 additions and 7 deletions
|
@ -776,16 +776,18 @@ PClass *PClass::FindClassTentative(FName name)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int PClass::FindVirtualIndex(FName name, PPrototype *proto)
|
int PClass::FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc)
|
||||||
{
|
{
|
||||||
|
auto proto = variant->Proto;
|
||||||
for (unsigned i = 0; i < Virtuals.Size(); i++)
|
for (unsigned i = 0; i < Virtuals.Size(); i++)
|
||||||
{
|
{
|
||||||
if (Virtuals[i]->Name == name)
|
if (Virtuals[i]->Name == name)
|
||||||
{
|
{
|
||||||
auto vproto = Virtuals[i]->Proto;
|
auto vproto = Virtuals[i]->Proto;
|
||||||
if (vproto->ReturnTypes.Size() != proto->ReturnTypes.Size() ||
|
if (vproto->ReturnTypes.Size() != proto->ReturnTypes.Size() ||
|
||||||
vproto->ArgumentTypes.Size() != proto->ArgumentTypes.Size())
|
vproto->ArgumentTypes.Size() < proto->ArgumentTypes.Size())
|
||||||
{
|
{
|
||||||
|
|
||||||
continue; // number of parameters does not match, so it's incompatible
|
continue; // number of parameters does not match, so it's incompatible
|
||||||
}
|
}
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
|
@ -808,7 +810,26 @@ int PClass::FindVirtualIndex(FName name, PPrototype *proto)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!fail) return i;
|
if (!fail)
|
||||||
|
{
|
||||||
|
if (vproto->ArgumentTypes.Size() > proto->ArgumentTypes.Size() && parentfunc)
|
||||||
|
{
|
||||||
|
// Check if the difference between both functions is only some optional arguments.
|
||||||
|
for (unsigned a = proto->ArgumentTypes.Size(); a < vproto->ArgumentTypes.Size(); a++)
|
||||||
|
{
|
||||||
|
if (!(parentfunc->Variants[0].ArgFlags[a] & VARF_Optional)) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo: extend the prototype
|
||||||
|
for (unsigned a = proto->ArgumentTypes.Size(); a < vproto->ArgumentTypes.Size(); a++)
|
||||||
|
{
|
||||||
|
proto->ArgumentTypes.Push(vproto->ArgumentTypes[a]);
|
||||||
|
variant->ArgFlags.Push(parentfunc->Variants[0].ArgFlags[a]);
|
||||||
|
variant->ArgNames.Push(NAME_None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
void WriteAllFields(FSerializer &ar, const void *addr) const;
|
void WriteAllFields(FSerializer &ar, const void *addr) const;
|
||||||
bool ReadAllFields(FSerializer &ar, void *addr) const;
|
bool ReadAllFields(FSerializer &ar, void *addr) const;
|
||||||
void InitializeDefaults();
|
void InitializeDefaults();
|
||||||
int FindVirtualIndex(FName name, PPrototype *proto);
|
int FindVirtualIndex(FName name, PFunction::Variant *variant, PFunction *parentfunc);
|
||||||
PSymbol *FindSymbol(FName symname, bool searchparents) const;
|
PSymbol *FindSymbol(FName symname, bool searchparents) const;
|
||||||
PField *AddField(FName name, PType *type, uint32_t flags);
|
PField *AddField(FName name, PType *type, uint32_t flags);
|
||||||
|
|
||||||
|
|
|
@ -2694,7 +2694,9 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
||||||
|
|
||||||
if (forclass)
|
if (forclass)
|
||||||
{
|
{
|
||||||
int vindex = clstype->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto);
|
auto parentfunc = clstype->ParentClass? dyn_cast<PFunction>(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true)) : nullptr;
|
||||||
|
|
||||||
|
int vindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], parentfunc);
|
||||||
// specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types.
|
// specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types.
|
||||||
if (varflags & VARF_Override)
|
if (varflags & VARF_Override)
|
||||||
{
|
{
|
||||||
|
@ -2705,7 +2707,6 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto oldfunc = clstype->Virtuals[vindex];
|
auto oldfunc = clstype->Virtuals[vindex];
|
||||||
auto parentfunc = dyn_cast<PFunction>(clstype->ParentClass->VMType->Symbols.FindSymbol(sym->SymbolName, true));
|
|
||||||
if (parentfunc && parentfunc->mVersion > mVersion)
|
if (parentfunc && parentfunc->mVersion > mVersion)
|
||||||
{
|
{
|
||||||
Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
|
Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
|
||||||
|
@ -2765,7 +2766,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
||||||
}
|
}
|
||||||
else if (forclass)
|
else if (forclass)
|
||||||
{
|
{
|
||||||
int vindex = clstype->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto);
|
int vindex = clstype->FindVirtualIndex(sym->SymbolName, &sym->Variants[0], nullptr);
|
||||||
if (vindex != -1)
|
if (vindex != -1)
|
||||||
{
|
{
|
||||||
Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars());
|
Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars());
|
||||||
|
|
Loading…
Reference in a new issue