From def5e1d61b5b90fe1ed1979421950dac0ac5d038 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 12 Mar 2018 10:19:16 +0100 Subject: [PATCH] Added proper handling for default parameter values of virtual overrides Due to how the VM handles default parameters, these must always be identical to the parent to prevent undefined behavior. So now, if such parameters are encountered, the compiler will either abort (for script version >= 3.3) or print a warning (for older versions.) Any defaults being specified for older versions will be ignored, though, and the defaults of the parent function be copied to the override. --- src/scripting/zscript/zcc_compile.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index e4773f1c68..0722ed6945 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2494,6 +2494,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool bool hasoptionals = false; if (p != nullptr) { + bool overridemsg = false; do { int elementcount = 1; @@ -2528,6 +2529,22 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool { flags |= VARF_Optional; hasoptionals = true; + + if ((varflags & VARF_Override) && !overridemsg) + { + // This is illegal, but in older compilers wasn't checked, so there it has to be demoted to a warning. + // Virtual calls always need to get their defaults from the base virtual method. + if (mVersion >= MakeVersion(3, 3)) + { + Error(p, "Default values for parameter of virtual override not allowed"); + } + else + { + Warn(p, "Default values for parameter of virtual override will be ignored!"); + } + overridemsg = true; + } + FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false); FCompileContext ctx(OutNamespace, c->Type(), false); @@ -2721,6 +2738,13 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool clstype->Virtuals[vindex] = sym->Variants[0].Implementation; sym->Variants[0].Implementation->VirtualIndex = vindex; sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags; + + // Defaults must be identical to parent class + if (parentfunc->Variants[0].Implementation->DefaultArgs.Size() > 0) + { + Printf("Copying defaults from %s to %s\n", parentfunc->Variants[0].Implementation->PrintableName.GetChars(), sym->Variants[0].Implementation->PrintableName.GetChars()); + sym->Variants[0].Implementation->DefaultArgs = parentfunc->Variants[0].Implementation->DefaultArgs; + } } } else