Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -144,6 +144,9 @@ - Fix assert that fails when the expression causing the this pointer to be captured by a block is part of a constexpr if statement's branch and instantiation of the enclosing method causes the branch to be discarded. +- Fix __VA_OPT__ implementation so that it treats the concatenation of a + non-placemaker token and placemaker token as a non-placemaker token. + (`#60268 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Index: clang/lib/Lex/TokenLexer.cpp =================================================================== --- clang/lib/Lex/TokenLexer.cpp +++ clang/lib/Lex/TokenLexer.cpp @@ -500,8 +500,7 @@ // the first token in a __VA_OPT__ after a ##, delete the ##. assert(VCtx.isInVAOpt() && "should only happen inside a __VA_OPT__"); VCtx.hasPlaceholderAfterHashhashAtStart(); - } - if (RParenAfter) + } else if (RParenAfter) VCtx.hasPlaceholderBeforeRParen(); } continue; @@ -567,7 +566,7 @@ continue; } - if (RParenAfter) + if (RParenAfter && !NonEmptyPasteBefore) VCtx.hasPlaceholderBeforeRParen(); // If this is on the RHS of a paste operator, we've already copied the Index: clang/test/Preprocessor/macro_vaopt_p1042r1.cpp =================================================================== --- clang/test/Preprocessor/macro_vaopt_p1042r1.cpp +++ clang/test/Preprocessor/macro_vaopt_p1042r1.cpp @@ -1,30 +1,36 @@ - RUN: %clang_cc1 -E %s -pedantic -std=c++2a | FileCheck -strict-whitespace %s - -#define LPAREN() ( -#define G(Q) 42 -#define F1(R, X, ...) __VA_OPT__(G R X) ) -1: int x = F1(LPAREN(), 0, <:-); -// CHECK: 1: int x = 42; - -#define F2(...) f(0 __VA_OPT__(,) __VA_ARGS__) -#define EMP -2: F2(EMP) -// CHECK: 2: f(0 ) - -#define H3(X, ...) #__VA_OPT__(X##X X##X) -3: H3(, 0) -// CHECK: 3: "" - -#define H4(X, ...) __VA_OPT__(a X ## X) ## b -4: H4(, 1) -// CHECK: 4: a b - -#define H4B(X, ...) a ## __VA_OPT__(X ## X b) -4B: H4B(, 1) -// CHECK: 4B: a b - -#define H5A(...) __VA_OPT__()/**/__VA_OPT__() -#define H5B(X) a ## X ## b -#define H5C(X) H5B(X) -5: H5C(H5A()) -// CHECK: 5: ab + RUN: %clang_cc1 -E %s -pedantic -std=c++2a | FileCheck -strict-whitespace %s + +#define LPAREN() ( +#define G(Q) 42 +#define F1(R, X, ...) __VA_OPT__(G R X) ) +1: int x = F1(LPAREN(), 0, <:-); +// CHECK: 1: int x = 42; + +#define F2(...) f(0 __VA_OPT__(,) __VA_ARGS__) +#define EMP +2: F2(EMP) +// CHECK: 2: f(0 ) + +#define H3(X, ...) #__VA_OPT__(X##X X##X) +3: H3(, 0) +// CHECK: 3: "" + +#define H4(X, ...) __VA_OPT__(a X ## X) ## b +4: H4(, 1) +// CHECK: 4: a b + +#define H4B(X, ...) a ## __VA_OPT__(X ## X b) +4B: H4B(, 1) +// CHECK: 4B: a b + +#define H5A(...) __VA_OPT__()/**/__VA_OPT__() +#define H5B(X) a ## X ## b +#define H5C(X) H5B(X) +5: H5C(H5A()) +// CHECK: 5: ab + +namespace GH60268 { +#define H6(X, ...) __VA_OPT__(a ## X) ## b +6: H6(, 1); +// CHECK: 6: ab +}