cmGeneratorExpression: Fix parser for adjacent colon and comma

Update ParseGeneratorExpression to allow correct parsing of adjacent
colon and comma separators in either order.

Fixes: #27324
This commit is contained in:
Martin Duffy
2025-12-02 11:53:11 -05:00
parent b65b7687cc
commit 41c69f8c87
4 changed files with 35 additions and 29 deletions

View File

@@ -115,31 +115,9 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
emptyParamTermination = true;
}
while (this->it != this->Tokens.end() &&
this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
commaTokens.push_back(this->it);
parameters.resize(parameters.size() + 1);
assert(this->it != this->Tokens.end());
++this->it;
if (this->it == this->Tokens.end()) {
emptyParamTermination = true;
}
}
while (this->it != this->Tokens.end() &&
this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
extendText(*(parameters.end() - 1), this->it);
assert(this->it != this->Tokens.end());
++this->it;
}
while (this->it != this->Tokens.end() &&
this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
this->ParseContent(*(parameters.end() - 1));
if (this->it == this->Tokens.end()) {
break;
}
while (this->it != this->Tokens.end() &&
this->it->TokenType ==
cmGeneratorExpressionToken::CommaSeparator) {
auto handleCommaOrColon = [this, &commaTokens, &parameters,
&emptyParamTermination]() -> void {
if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
commaTokens.push_back(this->it);
parameters.resize(parameters.size() + 1);
assert(this->it != this->Tokens.end());
@@ -147,14 +125,32 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
if (this->it == this->Tokens.end()) {
emptyParamTermination = true;
}
}
while (this->it != this->Tokens.end() &&
this->it->TokenType ==
cmGeneratorExpressionToken::ColonSeparator) {
} else if (this->it->TokenType ==
cmGeneratorExpressionToken::ColonSeparator) {
extendText(*(parameters.end() - 1), this->it);
assert(this->it != this->Tokens.end());
++this->it;
}
};
while (
this->it != this->Tokens.end() &&
(this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator ||
this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)) {
handleCommaOrColon();
}
while (this->it != this->Tokens.end() &&
this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
this->ParseContent(*(parameters.end() - 1));
if (this->it == this->Tokens.end()) {
break;
}
while (
this->it != this->Tokens.end() &&
(this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator ||
this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)) {
handleCommaOrColon();
}
}
if (this->it != this->Tokens.end() &&
this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {

View File

@@ -0,0 +1,6 @@
file(READ "${RunCMake_TEST_BINARY_DIR}/LIST-edgecases.txt" content)
set(expected "a;b;c:;d\na;b;c;:d")
if(NOT content STREQUAL expected)
set(RunCMake_TEST_FAILED "actual content:\n [[${content}]]\nbut expected:\n [[${expected}]]")
endif()

View File

@@ -0,0 +1,3 @@
set(ls1 "$<LIST:APPEND,a,b,c:,d>")
set(ls2 "$<LIST:APPEND,a,b,c,:d>")
file(GENERATE OUTPUT LIST-edgecases.txt CONTENT ${ls1}\n${ls2})

View File

@@ -56,6 +56,7 @@ run_cmake(FILTER-empty)
run_cmake(FILTER-InvalidOperator)
run_cmake(FILTER-Exclude)
run_cmake(FILTER-Include)
run_cmake(LIST-edgecases)
function(run_cmake_build test)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)