Issue 1135: Adjacent ## preprocessing tokens in a macro definition

Authors: Jay Ghiron
Date: 2026-11-12
Submitted against: C23
Status: Open
Cross-references: 0017.22

Consider the following:

#define F(X)+X####X+
F()

What does this expand to? Specifically, this will do concatenation with a placemarker preprocessing token and a ## preprocessing token. So depending upon which ## gets evaluated first it will be +##<placemarker>+ or +<placemarker>##+ after the first concatenation. Since the remaining ## preprocessing token was in the replacement list, should this do concatenation again? In either evaluation order the two possible interpretations are the same. If concatenation happens again, the result is two + preprocessing tokens. If concatenation does not happen again, the result is a + preprocessing token, then a ## preprocessing token, and then a + preprocessing token. GCC, Clang, EDG, and TCC all agree that this should do concatenation again, MSVC crashes when attempting to preprocess this macro with its new preprocessor. See also DR 17 question twenty two, that was answered as two concatenated # preprocessing tokens not doing concatenation after becoming a ## preprocessing token. If there are no surrounding preprocessing tokens, the behavior is unclear if concatenation does happen again:

#define G(X)X####X
G()

GCC, Clang, EDG, and TCC all agree that this should expand to nothing, MSVC crashes when attempting to preprocess this macro with its new preprocessor. Though to reach the interpretation that this expands to nothing, after the first concatenation the <placemarker>## or ##<placemarker> needs to do concatenation somehow despite one of the preprocessing tokens to concatenate not being present. In the following slightly different scenario there is disagreement among compilers:

#define H(X)+X####+
int main(){
int x=0;
H()x;
return x;
}

This is invalid if the second ## is evaluated first, though all compilers I have tested do not do that. Under the interpretation that concatenation happens again, if the first ## is evaluated first then +<placemarker>####+ should become +##+ and then one preprocessing token ++. Clang appears to do this, so it returns one from this program. GCC, EDG, and TCC all return zero instead indicating that they did not concatenate the + preprocessing tokens but did still remove the ## between the + preprocessing tokens. MSVC like before crashes when attempting to preprocess this macro with its new preprocessor.