mirror of https://github.com/ZDoom/gzdoom.git
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
|
@ -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 New Issue