From 4271677e154ed330445117b8e5e2aec43820cec0 Mon Sep 17 00:00:00 2001 From: William Roy Date: Sat, 31 Oct 2026 04:54:46 -0400 Subject: [PATCH] fix: Paste tokens in arguments of nested macros (#1062) --- .../Parsing/Impl/DefinesStreamProxy.cpp | 20 ++++++++++++++++++- .../Parsing/Impl/DefinesStreamProxyTests.cpp | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp b/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp index c2e20fb29..db3244476 100644 --- a/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp +++ b/src/Parser/Parsing/Impl/DefinesStreamProxy.cpp @@ -7,6 +7,7 @@ #include "Parsing/Simple/SimpleExpressionInterpreter.h" #include "Utils/StringUtils.h" +#include #include #include #include @@ -879,8 +880,25 @@ void DefinesStreamProxy::ExpandMacro(ParserLine& line, const Define* macro, const std::vector& parameterValues) { + std::vector pastedValues; + const auto* values = ¶meterValues; + if (std::ranges::any_of(parameterValues, + [](const std::string& value) + { + return value.find("##") != std::string::npos; + })) + { + pastedValues = parameterValues; + for (auto& value : pastedValues) + { + if (value.find("##") != std::string::npos) + ProcessTokenPastingOperators(line, linePos, value); + } + values = &pastedValues; + } + std::ostringstream rawOutput; - InsertMacroParameters(rawOutput, macro, parameterValues); + InsertMacroParameters(rawOutput, macro, *values); std::string str = rawOutput.str(); ProcessNestedMacros(line, linePos, callstack, str); diff --git a/test/ParserTests/Parsing/Impl/DefinesStreamProxyTests.cpp b/test/ParserTests/Parsing/Impl/DefinesStreamProxyTests.cpp index a3a776467..be5e48636 100644 --- a/test/ParserTests/Parsing/Impl/DefinesStreamProxyTests.cpp +++ b/test/ParserTests/Parsing/Impl/DefinesStreamProxyTests.cpp @@ -1127,6 +1127,26 @@ namespace test::parsing::impl::defines_stream_proxy REQUIRE(proxy.Eof()); } + TEST_CASE("DefinesStreamProxy: Can use token-pasting operator in arguments of nested macros", "[parsing][parsingstream]") + { + const std::vector lines{ + "#define s(t) #t", + "#define tag(id) s(id##_tag)", + "#define outer(list) tag(list##_member0)", + "outer(party)", + }; + + MockParserLineStream mockStream(lines); + DefinesStreamProxy proxy(&mockStream); + + ExpectLine(&proxy, 1, ""); + ExpectLine(&proxy, 2, ""); + ExpectLine(&proxy, 3, ""); + ExpectLine(&proxy, 4, "\"party_member0_tag\""); + + REQUIRE(proxy.Eof()); + } + TEST_CASE("DefinesStreamProxy: Can use token-pasting operator with string and stringization outside macro", "[parsing][parsingstream]") { const std::vector lines{