diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 4d30e8459..635488f26 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6706,11 +6706,28 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) AddressRequested = true; if (writable != nullptr) { - *writable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) && + // [ZZ] original check. + bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) && (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast(classx->ValueType)->IsConst)); // [ZZ] self in a const function is not writable. - if ((classx->ExprType == EFX_Self) && (ctx.Function && (ctx.Function->Variants[0].Flags & VARF_ReadOnly))) - *writable = false; + if (bWritable) // don't do complex checks on early fail + { + if ((classx->ExprType == EFX_Self) && (ctx.Function && (ctx.Function->Variants[0].Flags & VARF_ReadOnly))) + bWritable = false; + } + // [ZZ] plain data "inherits" scope of whatever it was defined in. + if (bWritable) // don't do complex checks on early fail + { + if (ctx.Function && FString(ctx.Function->SymbolName) == FString("DrawPowerup")) + Printf("field type = %d\n", BarrierSide); + int outerflags = 0; + if (ctx.Function) + outerflags = ctx.Function->Variants[0].Flags; + FScopeBarrier scopeBarrier(outerflags, FScopeBarrier::FlagsFromSide(BarrierSide), membervar->SymbolName.GetChars()); + if (!scopeBarrier.writable) + bWritable = false; + } + *writable = bWritable; } return true; } @@ -6741,6 +6758,15 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) return x->Resolve(ctx); } + // [ZZ] support magic + BarrierSide = FScopeBarrier::SideFromFlags(membervar->Flags); + if (classx->ExprType == EFX_StructMember || classx->ExprType == EFX_ClassMember) + { + FxStructMember* pmember = (FxStructMember*)classx; + if (BarrierSide == FScopeBarrier::Side_PlainData && pmember) + BarrierSide = pmember->BarrierSide; + } + if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { PPointer *ptrtype = dyn_cast(classx->ValueType); diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index c8120f4d1..ee43a0052 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -93,7 +93,7 @@ struct FScopeBarrier int sidelast; // Note: the same object can't be both UI and Play. This is checked explicitly in the field construction and will cause esoteric errors here if found. - int SideFromFlags(int flags) + static int SideFromFlags(int flags) { if (flags & VARF_UI) return Side_UI; @@ -102,8 +102,22 @@ struct FScopeBarrier return Side_PlainData; } + // + static int FlagsFromSide(int side) + { + switch (side) + { + case Side_Play: + return VARF_Play; + case Side_UI: + return VARF_UI; + default: + return 0; + } + } + // used for errors - const char* StringFromSide(int side) + static const char* StringFromSide(int side) { switch (side) { @@ -1451,6 +1465,7 @@ public: PField *membervar; bool AddressRequested = false; bool AddressWritable = true; + int BarrierSide = -1; // [ZZ] some magic FxMemberBase(EFxType type, PField *f, const FScriptPosition &p); };