mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
Disallow creation of abstract classes outside of their own class (this is so that modders can create their own factory methods, not just for native)
This commit is contained in:
parent
363990a105
commit
7d3663500f
4 changed files with 19 additions and 4 deletions
|
@ -205,7 +205,7 @@ enum EObjectFlags
|
||||||
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
|
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
|
||||||
OF_Spawned = 1 << 12, // Thinker was spawned at all (some thinkers get deleted before spawning)
|
OF_Spawned = 1 << 12, // Thinker was spawned at all (some thinkers get deleted before spawning)
|
||||||
OF_Released = 1 << 13, // Object was released from the GC system and should not be processed by GC function
|
OF_Released = 1 << 13, // Object was released from the GC system and should not be processed by GC function
|
||||||
OF_Abstract = 1 << 14, // Marks a class that cannot be created with CreateNew
|
OF_Abstract = 1 << 14, // Marks a class that cannot be created with new() function
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T> class TObjPtr;
|
template<class T> class TObjPtr;
|
||||||
|
|
|
@ -5023,6 +5023,7 @@ FxNew::FxNew(FxExpression *v)
|
||||||
{
|
{
|
||||||
val = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), v, false);
|
val = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), v, false);
|
||||||
ValueType = NewPointer(RUNTIME_CLASS(DObject));
|
ValueType = NewPointer(RUNTIME_CLASS(DObject));
|
||||||
|
CallingClass = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -5047,6 +5048,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx)
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(val, ctx);
|
SAFE_RESOLVE(val, ctx);
|
||||||
|
|
||||||
|
CallingClass = (PClass*)ctx.Class;
|
||||||
if (!val->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
if (!val->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Class type expected");
|
ScriptPosition.Message(MSG_ERROR, "Class type expected");
|
||||||
|
@ -5058,6 +5060,7 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx)
|
||||||
auto cls = static_cast<PClass *>(static_cast<FxConstant*>(val)->GetValue().GetPointer());
|
auto cls = static_cast<PClass *>(static_cast<FxConstant*>(val)->GetValue().GetPointer());
|
||||||
ValueType = NewPointer(cls);
|
ValueType = NewPointer(cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5072,7 +5075,7 @@ ExpEmit FxNew::Emit(VMFunctionBuilder *build)
|
||||||
ExpEmit from = val->Emit(build);
|
ExpEmit from = val->Emit(build);
|
||||||
from.Free(build);
|
from.Free(build);
|
||||||
ExpEmit to(build, REGT_POINTER);
|
ExpEmit to(build, REGT_POINTER);
|
||||||
build->Emit(from.Konst ? OP_NEW_K : OP_NEW, to.RegNum, from.RegNum);
|
build->Emit(from.Konst ? OP_NEW_K : OP_NEW, to.RegNum, from.RegNum, build->GetConstantAddress(CallingClass, ATAG_OBJECT));
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7527,8 +7530,18 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAME_New:
|
case NAME_New:
|
||||||
if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition))
|
if (CheckArgSize(MethodName, ArgList, 0, 1, ScriptPosition))
|
||||||
{
|
{
|
||||||
|
// [ZZ] allow implicit new() call to mean "create current class instance"
|
||||||
|
if (!ArgList.Size() && !ctx.Class->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Cannot use implicit new() in a struct");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else if (!ArgList.Size())
|
||||||
|
ArgList.Push(new FxConstant((PClass*)ctx.Class, NewClassPointer((PClass*)ctx.Class), ScriptPosition));
|
||||||
|
|
||||||
func = new FxNew(ArgList[0]);
|
func = new FxNew(ArgList[0]);
|
||||||
ArgList[0] = nullptr;
|
ArgList[0] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1208,6 +1208,7 @@ private:
|
||||||
class FxNew : public FxExpression
|
class FxNew : public FxExpression
|
||||||
{
|
{
|
||||||
FxExpression *val;
|
FxExpression *val;
|
||||||
|
PClass *CallingClass;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -787,7 +787,8 @@ begin:
|
||||||
{
|
{
|
||||||
b = B;
|
b = B;
|
||||||
PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[b] : konsta[b].v);
|
PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[b] : konsta[b].v);
|
||||||
if (cls->ObjectFlags & OF_Abstract) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
|
PClass *callingcls = (PClass*)konsta[C].o; // [ZZ] due to how this is set, it's always const
|
||||||
|
if ((cls->ObjectFlags & OF_Abstract) && callingcls != cls) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s outside of that class", cls->TypeName.GetChars());
|
||||||
reg.a[a] = cls->CreateNew();
|
reg.a[a] = cls->CreateNew();
|
||||||
reg.atag[a] = ATAG_OBJECT;
|
reg.atag[a] = ATAG_OBJECT;
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
|
|
Loading…
Reference in a new issue