Static virtualscope checking. This is possible, because virtualscope can't produce false positives (data readable for everyone), only false negatives (which are handled at runtime later)
This commit is contained in:
parent
12aa18a92b
commit
b5ab011bb9
11 changed files with 59 additions and 22 deletions
|
|
@ -1007,6 +1007,7 @@ decl_flag(X) ::= VARARG(T). { X.Int = ZCC_VarArg; X.SourceLoc = T.SourceLoc;
|
|||
decl_flag(X) ::= UI(T). { X.Int = ZCC_UIFlag; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= PLAY(T). { X.Int = ZCC_Play; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= CLEARSCOPE(T). { X.Int = ZCC_ClearScope; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= VIRTUALSCOPE(T). { X.Int = ZCC_VirtualScope; X.SourceLoc = T.SourceLoc; }
|
||||
|
||||
func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); }
|
||||
func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; }
|
||||
|
|
|
|||
|
|
@ -1273,7 +1273,7 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
|
|||
FString ZCCCompiler::FlagsToString(uint32_t flags)
|
||||
{
|
||||
|
||||
const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "const", "abstract", "extend", "virtual", "override", "transient", "vararg", "nonew", "ui", "play", "clearscope" };
|
||||
const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "const", "abstract", "extend", "virtual", "override", "transient", "vararg", "nonew", "ui", "play", "clearscope", "virtualscope" };
|
||||
FString build;
|
||||
|
||||
for (size_t i = 0; i < countof(flagnames); i++)
|
||||
|
|
@ -2130,11 +2130,13 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
if (f->Flags & ZCC_FuncConst)
|
||||
varflags = (varflags&~(VARF_Play | VARF_UI)); // const implies clearscope. this is checked a bit later to also not have ZCC_Play/ZCC_UIFlag.
|
||||
if (f->Flags & ZCC_UIFlag)
|
||||
varflags = (varflags&~VARF_Play) | VARF_UI;
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI);
|
||||
if (f->Flags & ZCC_Play)
|
||||
varflags = (varflags&~VARF_UI) | VARF_Play;
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play);
|
||||
if (f->Flags & ZCC_ClearScope)
|
||||
varflags = (varflags&~(VARF_Play | VARF_UI));
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData);
|
||||
if (f->Flags & ZCC_VirtualScope)
|
||||
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Virtual);
|
||||
|
||||
// [ZZ] supporting const self for actors is quite a cumbersome task because there's no concept of a const pointer (?)
|
||||
// either way, it doesn't make sense, because you can call any method on a readonly class instance.
|
||||
|
|
@ -2194,14 +2196,20 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
Error(f, "'Const' on a static method is not supported");
|
||||
}
|
||||
|
||||
// you can't have a const function belonging to either ui or play.
|
||||
// const is intended for plain data to signify that you can call a method on readonly variable.
|
||||
if ((f->Flags & ZCC_FuncConst) && (f->Flags & (ZCC_UIFlag | ZCC_Play)))
|
||||
// [ZZ] neither this
|
||||
if ((varflags&(VARF_VirtualScope | VARF_Method)) == VARF_VirtualScope) // non-method virtualscope function
|
||||
{
|
||||
Error(f, "Invalid combination of qualifiers %s on function %s", FlagsToString(f->Flags&(ZCC_FuncConst | ZCC_UIFlag | ZCC_Play)).GetChars(), FName(f->Name).GetChars());
|
||||
Error(f, "'VirtualScope' on a static method is not supported");
|
||||
}
|
||||
|
||||
static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope };
|
||||
// you can't have a const function belonging to either ui or play.
|
||||
// const is intended for plain data to signify that you can call a method on readonly variable.
|
||||
if ((f->Flags & ZCC_FuncConst) && (f->Flags & (ZCC_UIFlag | ZCC_Play | ZCC_VirtualScope)))
|
||||
{
|
||||
Error(f, "Invalid combination of qualifiers %s on function %s", FlagsToString(f->Flags&(ZCC_FuncConst | ZCC_UIFlag | ZCC_Play | ZCC_VirtualScope)).GetChars(), FName(f->Name).GetChars());
|
||||
}
|
||||
|
||||
static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope, ZCC_VirtualScope };
|
||||
excludeflags = 0;
|
||||
fc = 0;
|
||||
for (int i = 0; i < countof(excludescope); i++)
|
||||
|
|
@ -2406,9 +2414,11 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
sym->Variants[0].Implementation->Final = true;
|
||||
// [ZZ] unspecified virtual function inherits old scope. virtual function scope can't be changed.
|
||||
if (varflags & VARF_UI)
|
||||
sym->Variants[0].Implementation->ScopeUI = true;
|
||||
sym->Variants[0].Implementation->BarrierSide = FScopeBarrier::Side_UI;
|
||||
if (varflags & VARF_Play)
|
||||
sym->Variants[0].Implementation->ScopePlay = true;
|
||||
sym->Variants[0].Implementation->BarrierSide = FScopeBarrier::Side_Play;
|
||||
if (varflags & VARF_VirtualScope)
|
||||
sym->Variants[0].Implementation->BarrierSide = FScopeBarrier::Side_Virtual;
|
||||
if (varflags & VARF_ReadOnly)
|
||||
sym->Variants[0].Implementation->FuncConst = true;
|
||||
|
||||
|
|
@ -2430,7 +2440,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
Error(f, "Attempt to override final function %s", FName(f->Name).GetChars());
|
||||
}
|
||||
// you can't change ui/play/clearscope for a virtual method.
|
||||
if (f->Flags & (ZCC_UIFlag|ZCC_Play|ZCC_ClearScope))
|
||||
if (f->Flags & (ZCC_UIFlag|ZCC_Play|ZCC_ClearScope|ZCC_VirtualScope))
|
||||
{
|
||||
Error(f, "Attempt to change scope for virtual function %s", FName(f->Name).GetChars());
|
||||
}
|
||||
|
|
@ -2440,11 +2450,8 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
|
|||
Error(f, "Attempt to change const qualifier for virtual function %s", FName(f->Name).GetChars());
|
||||
}
|
||||
// inherit scope of original function if override not specified
|
||||
if (sym->Variants[0].Implementation->ScopeUI = oldfunc->ScopeUI)
|
||||
sym->Variants[0].Flags = (sym->Variants[0].Flags&~(VARF_Play)) | VARF_UI;
|
||||
else if (sym->Variants[0].Implementation->ScopePlay = oldfunc->ScopePlay)
|
||||
sym->Variants[0].Flags = (sym->Variants[0].Flags&~(VARF_UI)) | VARF_Play;
|
||||
else sym->Variants[0].Flags = (sym->Variants[0].Flags&~(VARF_UI | VARF_Play));
|
||||
sym->Variants[0].Implementation->BarrierSide = oldfunc->BarrierSide;
|
||||
sym->Variants[0].Flags = FScopeBarrier::ChangeSideInFlags(sym->Variants[0].Flags, oldfunc->BarrierSide);
|
||||
// inherit const from original function
|
||||
if (sym->Variants[0].Implementation->FuncConst = oldfunc->FuncConst)
|
||||
sym->Variants[0].Flags |= VARF_ReadOnly;
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ static void InitTokenMap()
|
|||
TOKENDEF (TK_UI, ZCC_UI);
|
||||
TOKENDEF (TK_Play, ZCC_PLAY);
|
||||
TOKENDEF (TK_ClearScope, ZCC_CLEARSCOPE);
|
||||
TOKENDEF (TK_VirtualScope, ZCC_VIRTUALSCOPE);
|
||||
TOKENDEF (TK_NoNew, ZCC_NONEW);
|
||||
TOKENDEF (TK_Override, ZCC_OVERRIDE);
|
||||
TOKENDEF (TK_Final, ZCC_FINAL);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ enum
|
|||
ZCC_UIFlag = 1 << 18, // there's also token called ZCC_UI
|
||||
ZCC_Play = 1 << 19,
|
||||
ZCC_ClearScope = 1 << 20,
|
||||
ZCC_VirtualScope = 1 << 21,
|
||||
};
|
||||
|
||||
// Function parameter modifiers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue