summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2022-08-22 14:10:56 (GMT)
committerMarc Chevrier <marc.chevrier@gmail.com>2022-09-03 21:10:01 (GMT)
commit838a5fae23cba0c9acf922164ff89fb6883d0f96 (patch)
tree27cf344771ff7266aa70cbf4ab3ddcba1d653a19
parent8f0e1f2111c046aaa240a54c211404747c911698 (diff)
downloadCMake-838a5fae23cba0c9acf922164ff89fb6883d0f96.zip
CMake-838a5fae23cba0c9acf922164ff89fb6883d0f96.tar.gz
CMake-838a5fae23cba0c9acf922164ff89fb6883d0f96.tar.bz2
return(): Propagate variables to result scope
Fixes: #23871
-rw-r--r--Help/command/block.rst1
-rw-r--r--Help/command/return.rst36
-rw-r--r--Help/command/set.rst6
-rw-r--r--Help/manual/cmake-policies.7.rst8
-rw-r--r--Help/policy/CMP0140.rst17
-rw-r--r--Help/release/dev/return-PROPAGATE.rst5
-rw-r--r--Source/cmBlockCommand.cxx15
-rw-r--r--Source/cmExecutionStatus.h17
-rw-r--r--Source/cmForEachCommand.cxx2
-rw-r--r--Source/cmFunctionCommand.cxx1
-rw-r--r--Source/cmIfCommand.cxx2
-rw-r--r--Source/cmMacroCommand.cxx2
-rw-r--r--Source/cmMakefile.cxx1
-rw-r--r--Source/cmPolicies.h4
-rw-r--r--Source/cmReturnCommand.cxx44
-rw-r--r--Source/cmWhileCommand.cxx2
-rw-r--r--Tests/RunCMake/return/CMP0140-NEW.cmake13
-rw-r--r--Tests/RunCMake/return/CMP0140-OLD.cmake8
-rw-r--r--Tests/RunCMake/return/CMP0140-WARN-result.txt1
-rw-r--r--Tests/RunCMake/return/CMP0140-WARN-stderr.txt12
-rw-r--r--Tests/RunCMake/return/CMP0140-WARN.cmake8
-rw-r--r--Tests/RunCMake/return/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/return/PropagateFromDirectory.cmake10
-rw-r--r--Tests/RunCMake/return/PropagateFromFunction.cmake142
-rw-r--r--Tests/RunCMake/return/PropagateNothing.cmake2
-rw-r--r--Tests/RunCMake/return/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/return/WrongArgument-result.txt1
-rw-r--r--Tests/RunCMake/return/WrongArgument-stderr.txt4
-rw-r--r--Tests/RunCMake/return/WrongArgument.cmake2
-rw-r--r--Tests/RunCMake/return/subdir/CMakeLists.txt5
30 files changed, 360 insertions, 22 deletions
diff --git a/Help/command/block.rst b/Help/command/block.rst
index f9d85c8..9d37deb 100644
--- a/Help/command/block.rst
+++ b/Help/command/block.rst
@@ -71,4 +71,5 @@ See Also
^^^^^^^^
* :command:`endblock`
+ * :command:`return`
* :command:`cmake_policy`
diff --git a/Help/command/return.rst b/Help/command/return.rst
index ec009d8..029fd05 100644
--- a/Help/command/return.rst
+++ b/Help/command/return.rst
@@ -5,7 +5,7 @@ Return from a file, directory or function.
.. code-block:: cmake
- return()
+ return([PROPAGATE <var-name>...])
Returns from a file, directory or function. When this command is
encountered in an included file (via :command:`include` or
@@ -16,5 +16,39 @@ deferred calls scheduled by :command:`cmake_language(DEFER)` are invoked and
control is returned to the parent directory if there is one. If return is
called in a function, control is returned to the caller of the function.
+``PROPAGATE``
+ .. versionadded:: 3.25
+
+ This option set or unset the specified variables in the parent directory or
+ function caller scope. This is equivalent to :command:`set(PARENT_SCOPE)` or
+ :command:`unset(PARENT_SCOPE)` commands.
+
+ The option ``PROPAGATE`` can be very useful in conjunction with the
+ :command:`block` command because the :command:`return` will cross over
+ various scopes created by the :command:`block` commands.
+
+ .. code-block:: cmake
+
+ function(MULTI_SCOPES RESULT_VARIABLE)
+ block(SCOPE_FOR VARIABLES)
+ # here set(PARENT_SCOPE) is not usable because it will not set the
+ # variable in the caller scope but in the parent scope of the block()
+ set(${RESULT_VARIABLE} "new-value")
+ return(PROPAGATE ${RESULT_VARIABLE})
+ endblock()
+ endfunction()
+
+ set(MY_VAR "initial-value")
+ multi_scopes(MY_VAR)
+ # here MY_VAR will holds "new-value"
+
+Policy :policy:`CMP0140` controls the behavior regarding the arguments of the
+command.
+
Note that a :command:`macro <macro>`, unlike a :command:`function <function>`,
is expanded in place and therefore cannot handle ``return()``.
+
+See Also
+^^^^^^^^
+
+ * :command:`block`
diff --git a/Help/command/set.rst b/Help/command/set.rst
index aa2ea55..5e05d9b 100644
--- a/Help/command/set.rst
+++ b/Help/command/set.rst
@@ -30,9 +30,9 @@ applicable to the case at hand). The previous state of the variable's value
stays the same in the current scope (e.g., if it was undefined before, it is
still undefined and if it had a value, it is still that value).
-The :command:`block(PROPAGATE)` command can be used as an alternate method to
-:command:`set(PARENT_SCOPE)` and :command:`unset(PARENT_SCOPE)` commands to
-update the parent scope.
+The :command:`block(PROPAGATE)` and :command:`return(PROPAGATE)` commands can
+be used as an alternate method to the :command:`set(PARENT_SCOPE)` and
+:command:`unset(PARENT_SCOPE)` commands to update the parent scope.
Set Cache Entry
^^^^^^^^^^^^^^^
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index f6ab0c7..a1133b9 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -52,6 +52,14 @@ to determine whether to report an error on use of deprecated macros or
functions.
+Policies Introduced by CMake 3.25
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0140: The return() command checks its arguments. </policy/CMP0140>
+
Policies Introduced by CMake 3.24
=================================
diff --git a/Help/policy/CMP0140.rst b/Help/policy/CMP0140.rst
new file mode 100644
index 0000000..2e2d0c3
--- /dev/null
+++ b/Help/policy/CMP0140.rst
@@ -0,0 +1,17 @@
+CMP0140
+-------
+
+.. versionadded:: 3.25
+
+The :command:`return` command checks its parameters.
+
+The ``OLD`` behavior for this policy is to ignore any parameters given to the
+command.
+The ``NEW`` behavior is to check validity of the parameters.
+
+This policy was introduced in CMake version 3.25.
+CMake version |release| warns when the policy is not set and uses
+``OLD`` behavior. Use the :command:`cmake_policy` command to set
+it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/release/dev/return-PROPAGATE.rst b/Help/release/dev/return-PROPAGATE.rst
new file mode 100644
index 0000000..7308d20
--- /dev/null
+++ b/Help/release/dev/return-PROPAGATE.rst
@@ -0,0 +1,5 @@
+return-PROPAGATE
+----------------
+
+* The :command:`return` command gains the capability to propagate variables to
+ the include directory of function caller scope. See policy :policy:`CMP0140`.
diff --git a/Source/cmBlockCommand.cxx b/Source/cmBlockCommand.cxx
index c358aa2..ec79149 100644
--- a/Source/cmBlockCommand.cxx
+++ b/Source/cmBlockCommand.cxx
@@ -73,6 +73,7 @@ public:
private:
cmMakefile* Makefile;
+ ScopeSet Scopes;
BlockScopePushPop BlockScope;
std::vector<std::string> VariableNames;
};
@@ -81,6 +82,7 @@ cmBlockFunctionBlocker::cmBlockFunctionBlocker(
cmMakefile* const mf, const ScopeSet& scopes,
std::vector<std::string> variableNames)
: Makefile{ mf }
+ , Scopes{ scopes }
, BlockScope{ mf, scopes }
, VariableNames{ std::move(variableNames) }
{
@@ -88,14 +90,8 @@ cmBlockFunctionBlocker::cmBlockFunctionBlocker(
cmBlockFunctionBlocker::~cmBlockFunctionBlocker()
{
- for (auto const& varName : this->VariableNames) {
- if (this->Makefile->IsNormalDefinitionSet(varName)) {
- this->Makefile->RaiseScope(varName,
- this->Makefile->GetDefinition(varName));
- } else {
- // unset variable in parent scope
- this->Makefile->RaiseScope(varName, nullptr);
- }
+ if (this->Scopes.contains(ScopeType::VARIABLES)) {
+ this->Makefile->RaiseScope(this->VariableNames);
}
}
@@ -118,7 +114,8 @@ bool cmBlockFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
cmExecutionStatus status(mf);
mf.ExecuteCommand(fn, status);
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ mf.RaiseScope(status.GetReturnVariables());
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
return true;
}
if (status.GetBreakInvoked()) {
diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h
index 0feaedf..ced3548 100644
--- a/Source/cmExecutionStatus.h
+++ b/Source/cmExecutionStatus.h
@@ -5,6 +5,7 @@
#include <cmConfigure.h> // IWYU pragma: keep
#include <string>
+#include <vector>
class cmMakefile;
@@ -27,8 +28,21 @@ public:
void SetError(std::string const& e) { this->Error = e; }
std::string const& GetError() const { return this->Error; }
- void SetReturnInvoked() { this->ReturnInvoked = true; }
+ void SetReturnInvoked()
+ {
+ this->Variables.clear();
+ this->ReturnInvoked = true;
+ }
+ void SetReturnInvoked(std::vector<std::string> variables)
+ {
+ this->Variables = std::move(variables);
+ this->ReturnInvoked = true;
+ }
bool GetReturnInvoked() const { return this->ReturnInvoked; }
+ const std::vector<std::string>& GetReturnVariables() const
+ {
+ return this->Variables;
+ }
void SetBreakInvoked() { this->BreakInvoked = true; }
bool GetBreakInvoked() const { return this->BreakInvoked; }
@@ -46,4 +60,5 @@ private:
bool BreakInvoked = false;
bool ContinueInvoked = false;
bool NestedError = false;
+ std::vector<std::string> Variables;
};
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index b9400c9..3465c23 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -260,7 +260,7 @@ auto cmForEachFunctionBlocker::invoke(
cmExecutionStatus status(mf);
mf.ExecuteCommand(func, status);
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
result.Break = true;
break;
}
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index 1359009..f4768b6 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -120,6 +120,7 @@ bool cmFunctionHelperCommand::operator()(
return false;
}
if (status.GetReturnInvoked()) {
+ makefile.RaiseScope(status.GetReturnVariables());
break;
}
}
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
index 0da72b1..c2a09c1 100644
--- a/Source/cmIfCommand.cxx
+++ b/Source/cmIfCommand.cxx
@@ -150,7 +150,7 @@ bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
cmExecutionStatus status(mf);
mf.ExecuteCommand(func, status);
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
return true;
}
if (status.GetBreakInvoked()) {
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index ef12487..47ad749 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -126,7 +126,7 @@ bool cmMacroHelperCommand::operator()(
return false;
}
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
return true;
}
if (status.GetBreakInvoked()) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 51a4b3b..760ed5f 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -789,6 +789,7 @@ void cmMakefile::RunListFile(cmListFile const& listFile,
break;
}
if (status.GetReturnInvoked()) {
+ this->RaiseScope(status.GetReturnVariables());
// Exit early due to return command.
break;
}
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index cb7402c..fdda31e 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -421,7 +421,9 @@ class cmMakefile;
SELECT( \
POLICY, CMP0139, \
"The if() command supports path comparisons using PATH_EQUAL operator.", \
- 3, 24, 0, cmPolicies::WARN)
+ 3, 24, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0140, "The return() command checks its arguments.", 3, \
+ 25, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
diff --git a/Source/cmReturnCommand.cxx b/Source/cmReturnCommand.cxx
index 5905669..765b772 100644
--- a/Source/cmReturnCommand.cxx
+++ b/Source/cmReturnCommand.cxx
@@ -2,12 +2,52 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmReturnCommand.h"
+#include <cm/string_view>
+#include <cmext/string_view>
+
#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
// cmReturnCommand
-bool cmReturnCommand(std::vector<std::string> const&,
+bool cmReturnCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- status.SetReturnInvoked();
+ if (!args.empty()) {
+ switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0140)) {
+ case cmPolicies::WARN:
+ status.GetMakefile().IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0140), '\n',
+ "return() checks its arguments when the policy is set to NEW. "
+ "Since the policy is not set the OLD behavior will be used so "
+ "the arguments will be ignored."));
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ return true;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ status.GetMakefile().IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat('\n', cmPolicies::GetPolicyWarning(cmPolicies::CMP0140)));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ default:
+ break;
+ }
+ if (args[0] != "PROPAGATE"_s) {
+ status.SetError(
+ cmStrCat("called with unsupported argument \"", args[0], '"'));
+ cmSystemTools::SetFatalErrorOccurred();
+ return false;
+ }
+ status.SetReturnInvoked({ args.begin() + 1, args.end() });
+ } else {
+ status.SetReturnInvoked();
+ }
return true;
}
diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx
index fb94273..e80d1fc 100644
--- a/Source/cmWhileCommand.cxx
+++ b/Source/cmWhileCommand.cxx
@@ -96,7 +96,7 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions,
cmExecutionStatus status(mf);
mf.ExecuteCommand(fn, status);
if (status.GetReturnInvoked()) {
- inStatus.SetReturnInvoked();
+ inStatus.SetReturnInvoked(status.GetReturnVariables());
return true;
}
if (status.GetBreakInvoked()) {
diff --git a/Tests/RunCMake/return/CMP0140-NEW.cmake b/Tests/RunCMake/return/CMP0140-NEW.cmake
new file mode 100644
index 0000000..eb6b85c
--- /dev/null
+++ b/Tests/RunCMake/return/CMP0140-NEW.cmake
@@ -0,0 +1,13 @@
+
+cmake_policy(SET CMP0140 NEW)
+
+function(FUNC)
+ set(VAR "set")
+ return(PROPAGATE VAR)
+endfunction()
+
+set(VAR "initial")
+func()
+if (NOT DEFINED VAR OR NOT VAR STREQUAL "set")
+ message(FATAL_ERROR "return(PROPAGATE) not handled correctly.")
+endif()
diff --git a/Tests/RunCMake/return/CMP0140-OLD.cmake b/Tests/RunCMake/return/CMP0140-OLD.cmake
new file mode 100644
index 0000000..8113a43
--- /dev/null
+++ b/Tests/RunCMake/return/CMP0140-OLD.cmake
@@ -0,0 +1,8 @@
+
+cmake_policy(SET CMP0140 OLD)
+
+function(FUNC)
+ return(PROPAGATE VAR)
+endfunction()
+
+func()
diff --git a/Tests/RunCMake/return/CMP0140-WARN-result.txt b/Tests/RunCMake/return/CMP0140-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/return/CMP0140-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/return/CMP0140-WARN-stderr.txt b/Tests/RunCMake/return/CMP0140-WARN-stderr.txt
new file mode 100644
index 0000000..ed4beb6
--- /dev/null
+++ b/Tests/RunCMake/return/CMP0140-WARN-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\) at CMP0140-WARN.cmake:[0-9]+ \(return\):
+ Policy CMP0140 is not set: The return\(\) command checks its arguments. Run
+ "cmake --help-policy CMP0140" for policy details. Use the cmake_policy
+ command to set the policy and suppress this warning.
+
+ return\(\) checks its arguments when the policy is set to NEW. Since the
+ policy is not set the OLD behavior will be used so the arguments will be
+ ignored.
+Call Stack \(most recent call first\):
+ CMP0140-WARN.cmake:[0-9]+ \(func\)
+ CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/return/CMP0140-WARN.cmake b/Tests/RunCMake/return/CMP0140-WARN.cmake
new file mode 100644
index 0000000..df2fc88
--- /dev/null
+++ b/Tests/RunCMake/return/CMP0140-WARN.cmake
@@ -0,0 +1,8 @@
+
+cmake_policy(VERSION 3.1)
+
+function(FUNC)
+ return(PROPAGATE VAR)
+endfunction()
+
+func()
diff --git a/Tests/RunCMake/return/CMakeLists.txt b/Tests/RunCMake/return/CMakeLists.txt
index ef2163c..6cc903f 100644
--- a/Tests/RunCMake/return/CMakeLists.txt
+++ b/Tests/RunCMake/return/CMakeLists.txt
@@ -1,3 +1,3 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.1...3.25)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/return/PropagateFromDirectory.cmake b/Tests/RunCMake/return/PropagateFromDirectory.cmake
new file mode 100644
index 0000000..9c820bb
--- /dev/null
+++ b/Tests/RunCMake/return/PropagateFromDirectory.cmake
@@ -0,0 +1,10 @@
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+
+add_subdirectory(subdir)
+
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC1")
+endif()
diff --git a/Tests/RunCMake/return/PropagateFromFunction.cmake b/Tests/RunCMake/return/PropagateFromFunction.cmake
new file mode 100644
index 0000000..1c12bc1
--- /dev/null
+++ b/Tests/RunCMake/return/PropagateFromFunction.cmake
@@ -0,0 +1,142 @@
+
+function(FUNC1)
+ set(VAR1 "set")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+endfunction()
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+func1()
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC1")
+endif()
+
+
+function(FUNC2)
+ block()
+ set(VAR1 "set")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+ endblock()
+endfunction()
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+func2()
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC2")
+endif()
+
+
+function(FUNC3)
+ block(SCOPE_FOR POLICIES)
+ set(VAR1 "set")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+ endblock()
+endfunction()
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+func3()
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC3")
+endif()
+
+
+function(FUNC4)
+ while(TRUE)
+ set(VAR1 "set")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+ endwhile()
+endfunction()
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+func4()
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC4")
+endif()
+
+
+function(FUNC5)
+ foreach(item IN ITEMS A B)
+ set(VAR1 "set")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+ endforeach()
+endfunction()
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+func5()
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC5")
+endif()
+
+
+function(FUNC6)
+ if(TRUE)
+ set(VAR1 "set")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+ endif()
+endfunction()
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+func6()
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC6")
+endif()
+
+
+function(FUNC7)
+ if(FALSE)
+ else()
+ set(VAR1 "set")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+ endif()
+endfunction()
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+func7()
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for FUNC7")
+endif()
+
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+cmake_language(CALL func7)
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for cmake_language(CALL FUNC7)")
+endif()
+
+
+set(VAR1 "initial")
+set(VAR2 "initial")
+cmake_language(EVAL CODE "
+ function(FUNC8)
+ set(VAR1 \"set\")
+ unset(VAR2)
+ return(PROPAGATE VAR1 VAR2)
+ endfunction()
+
+ func8()")
+if((NOT DEFINED VAR1 OR NOT VAR1 STREQUAL "set")
+ OR DEFINED VAR2)
+ message(SEND_ERROR "erroneous propagation for cmake_language(EVAL CODE)")
+endif()
diff --git a/Tests/RunCMake/return/PropagateNothing.cmake b/Tests/RunCMake/return/PropagateNothing.cmake
new file mode 100644
index 0000000..0ace58e
--- /dev/null
+++ b/Tests/RunCMake/return/PropagateNothing.cmake
@@ -0,0 +1,2 @@
+
+return(PROPAGATE)
diff --git a/Tests/RunCMake/return/RunCMakeTest.cmake b/Tests/RunCMake/return/RunCMakeTest.cmake
index 2cc6c9d..f9e06a5 100644
--- a/Tests/RunCMake/return/RunCMakeTest.cmake
+++ b/Tests/RunCMake/return/RunCMakeTest.cmake
@@ -1,3 +1,12 @@
include(RunCMake)
run_cmake(ReturnFromForeach)
+
+run_cmake(WrongArgument)
+run_cmake(PropagateNothing)
+run_cmake(PropagateFromFunction)
+run_cmake(PropagateFromDirectory)
+
+run_cmake(CMP0140-NEW)
+run_cmake(CMP0140-OLD)
+run_cmake(CMP0140-WARN)
diff --git a/Tests/RunCMake/return/WrongArgument-result.txt b/Tests/RunCMake/return/WrongArgument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/return/WrongArgument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/return/WrongArgument-stderr.txt b/Tests/RunCMake/return/WrongArgument-stderr.txt
new file mode 100644
index 0000000..4d1c5ad
--- /dev/null
+++ b/Tests/RunCMake/return/WrongArgument-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at WrongArgument.cmake:[0-9]+ \(return\):
+ return called with unsupported argument "WRONG_ARG"
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/return/WrongArgument.cmake b/Tests/RunCMake/return/WrongArgument.cmake
new file mode 100644
index 0000000..d03b19f
--- /dev/null
+++ b/Tests/RunCMake/return/WrongArgument.cmake
@@ -0,0 +1,2 @@
+
+return(WRONG_ARG)
diff --git a/Tests/RunCMake/return/subdir/CMakeLists.txt b/Tests/RunCMake/return/subdir/CMakeLists.txt
new file mode 100644
index 0000000..e575d47
--- /dev/null
+++ b/Tests/RunCMake/return/subdir/CMakeLists.txt
@@ -0,0 +1,5 @@
+
+set(VAR1 "set")
+unset(VAR2)
+
+return(PROPAGATE VAR1 VAR2)