From 6ad965abb57e04ffa407f4215ae7d919cc966679 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 10 Nov 2019 11:14:08 +0200 Subject: [PATCH] - improved handling of return value mismatches Prohibit returning more values than declared in function The exception is a void function returning one value, but only for compatibility with old scripts https://forum.zdoom.org/viewtopic.php?t=66341 --- src/scripting/backend/codegen.cpp | 39 ++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 38f3aea16e..ac5f681631 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -10716,27 +10716,44 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) PPrototype *retproto; - if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() == 0 && ctx.ReturnProto->ReturnTypes.Size() != Args.Size()) + const bool hasProto = ctx.ReturnProto != nullptr; + const unsigned protoRetCount = hasProto ? ctx.ReturnProto->ReturnTypes.Size() : 0; + const unsigned retCount = Args.Size(); + int mismatchSeverity = -1; + + if (hasProto) { - int severity = ctx.Version >= MakeVersion(3, 7) ? MSG_ERROR : MSG_WARNING; - ScriptPosition.Message(severity, "Incorrect number of return values. Got %u, but expected %u", Args.Size(), ctx.ReturnProto->ReturnTypes.Size()); - if (severity == MSG_ERROR) + if (protoRetCount == 0 && retCount == 1) + { + // Handle the case with void function returning something, but only for one value + // It was accepted in previous versions, do not abort with fatal error when compiling old scripts + mismatchSeverity = ctx.Version >= MakeVersion(3, 7) ? MSG_ERROR : MSG_WARNING; + } + else if (protoRetCount < retCount) + { + mismatchSeverity = MSG_ERROR; + } + } + + if (mismatchSeverity != -1) + { + ScriptPosition.Message(mismatchSeverity, "Incorrect number of return values. Got %u, but expected %u", Args.Size(), ctx.ReturnProto->ReturnTypes.Size()); + if (mismatchSeverity == MSG_ERROR) { delete this; return nullptr; } - // For older script versions this must fall through. } - - if (Args.Size() == 0) + + if (retCount == 0) { TArray none(0); retproto = NewPrototype(none, none); } - else if (Args.Size() == 1) + else if (retCount == 1) { // If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.) - if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() > 0 && ctx.Function->SymbolName != NAME_None) + if (hasProto && protoRetCount > 0 && ctx.Function->SymbolName != NAME_None) { Args[0] = new FxTypeCast(Args[0], ctx.ReturnProto->ReturnTypes[0], false, false); Args[0] = Args[0]->Resolve(ctx); @@ -10746,7 +10763,7 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) } else { - for (unsigned i = 0; i < Args.Size(); i++) + for (unsigned i = 0; i < retCount; i++) { Args[i] = new FxTypeCast(Args[i], ctx.ReturnProto->ReturnTypes[i], false, false); Args[i] = Args[i]->Resolve(ctx); @@ -11906,4 +11923,4 @@ ExpEmit FxOutVarDereference::Emit(VMFunctionBuilder *build) selfEmit.Free(build); return out; -} \ No newline at end of file +}