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:
ZZYZX 2017-02-18 04:07:12 +02:00
commit b5ab011bb9
11 changed files with 59 additions and 22 deletions

View file

@ -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;