Commit b5f8113c authored by Kyle Edwards's avatar Kyle Edwards

Genex: Add policy to handle empty list items in $<IN_LIST:...>

The old behavior of $<IN_LIST:...> is inconsistent with that of
if(IN_LIST), in that it does not find an empty search item even if
the list contains empty items. This change adds a new policy to
correctly handle empty items and make the behavior more consistent
with if(IN_LIST).

Fixes: #18556
parent 1dc85a66
......@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.14
.. toctree::
:maxdepth: 1
CMP0085: IN_LIST generator expression handles empty list items. </policy/CMP0085>
CMP0084: The FindQt module does not exist for find_package(). </policy/CMP0084>
CMP0083: Add PIE options when linking executable. </policy/CMP0083>
CMP0082: Install rules from add_subdirectory() are interleaved with those in caller. </policy/CMP0082>
......
CMP0085
-------
``$<IN_LIST:...>`` handles empty list items.
In CMake 3.13 and lower, the ``$<IN_LIST:...>`` generator expression always
returned ``0`` if the first argument was empty, even if the list contained an
empty item. This behavior is inconsistent with the ``IN_LIST`` behavior of
:command:`if`, which this generator expression is meant to emulate. CMake 3.14
and later handles this case correctly.
The ``OLD`` behavior of this policy is for ``$<IN_LIST:...>`` to always return
``0`` if the first argument is empty. The ``NEW`` behavior is to return ``1``
if the first argument is empty and the list contains an empty item.
This policy was introduced in CMake version 3.14. 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
genex-in_list-empty-args
------------------------
* The $<IN_LIST:...> generator expression now correctly handles an empty
argument. See :policy:`CMP0085` for details.
......@@ -283,14 +283,39 @@ static const struct InListNode : public cmGeneratorExpressionNode
std::string Evaluate(
const std::vector<std::string>& parameters,
cmGeneratorExpressionContext* /*context*/,
cmGeneratorExpressionContext* context,
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
std::vector<std::string> values;
cmSystemTools::ExpandListArgument(parameters[1], values);
if (values.empty()) {
return "0";
std::vector<std::string> values, checkValues;
bool check = false;
switch (context->LG->GetPolicyStatus(cmPolicies::CMP0085)) {
case cmPolicies::WARN:
if (parameters.front().empty()) {
check = true;
cmSystemTools::ExpandListArgument(parameters[1], checkValues, true);
}
CM_FALLTHROUGH;
case cmPolicies::OLD:
cmSystemTools::ExpandListArgument(parameters[1], values);
if (check && values != checkValues) {
std::ostringstream e;
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
<< "\nSearch Item:\n \"" << parameters.front()
<< "\"\nList:\n \"" << parameters[1] << "\"\n";
context->LG->GetCMakeInstance()->IssueMessage(
cmake::AUTHOR_WARNING, e.str(), context->Backtrace);
return "0";
}
if (values.empty()) {
return "0";
}
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
cmSystemTools::ExpandListArgument(parameters[1], values, true);
break;
}
return std::find(values.cbegin(), values.cend(), parameters.front()) ==
......
......@@ -249,7 +249,9 @@ class cmMakefile;
0, cmPolicies::WARN) \
SELECT(POLICY, CMP0084, \
"The FindQt module does not exist for find_package().", 3, 14, 0, \
cmPolicies::WARN)
cmPolicies::WARN) \
SELECT(POLICY, CMP0085, "$<IN_LIST:...> handles empty list items.", 3, 14, \
0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
......
file(READ "${RunCMake_TEST_BINARY_DIR}/CMP0085-NEW-generated.txt" content)
set(expected "101011")
if(NOT content STREQUAL expected)
set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
endif()
cmake_policy(SET CMP0070 NEW)
file(GENERATE OUTPUT CMP0085-NEW-generated.txt CONTENT
"$<IN_LIST:,>$<IN_LIST:,a>$<IN_LIST:,;a>$<IN_LIST:a,>$<IN_LIST:a,a>$<IN_LIST:a,;a>"
)
file(READ "${RunCMake_TEST_BINARY_DIR}/CMP0085-OLD-generated.txt" content)
set(expected "000011")
if(NOT content STREQUAL expected)
set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
endif()
cmake_policy(SET CMP0070 NEW)
file(GENERATE OUTPUT CMP0085-OLD-generated.txt CONTENT
"$<IN_LIST:,>$<IN_LIST:,a>$<IN_LIST:,;a>$<IN_LIST:a,>$<IN_LIST:a,a>$<IN_LIST:a,;a>"
)
file(READ "${RunCMake_TEST_BINARY_DIR}/CMP0085-WARN-generated.txt" content)
set(expected "000011")
if(NOT content STREQUAL expected)
set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
endif()
CMake Warning \(dev\) at CMP0085-WARN\.cmake:[0-9]+ \(file\):
Policy CMP0085 is not set: \$<IN_LIST:\.\.\.> handles empty list items\. Run
"cmake --help-policy CMP0085" for policy details\. Use the cmake_policy
command to set the policy and suppress this warning\.
Search Item:
""
List:
""
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.
CMake Warning \(dev\) at CMP0085-WARN\.cmake:[0-9]+ \(file\):
Policy CMP0085 is not set: \$<IN_LIST:\.\.\.> handles empty list items\. Run
"cmake --help-policy CMP0085" for policy details\. Use the cmake_policy
command to set the policy and suppress this warning\.
Search Item:
""
List:
";a"
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.
cmake_policy(SET CMP0070 NEW)
file(GENERATE OUTPUT CMP0085-WARN-generated.txt CONTENT
"$<IN_LIST:,>$<IN_LIST:,a>$<IN_LIST:,;a>$<IN_LIST:a,>$<IN_LIST:a,a>$<IN_LIST:a,;a>"
)
......@@ -61,3 +61,13 @@ if(LINKER_SUPPORTS_PDB)
else()
run_cmake(NonValidCompiler-TARGET_PDB_FILE)
endif()
set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0085:STRING=OLD)
run_cmake(CMP0085-OLD)
unset(RunCMake_TEST_OPTIONS)
run_cmake(CMP0085-WARN)
set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0085:STRING=NEW)
run_cmake(CMP0085-NEW)
unset(RunCMake_TEST_OPTIONS)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment