Why are argument substitutions not replaced during rescanning?
- by James McNellis
Consider the following macro definitions and invocation:
#define x x[0]
#define y(arg) arg
y(x)
This invocation expands to x[0] (tested on Visual C++ 2010, g++ 4.1, mcpp 2.7.2, and Wave).
Why? Specifically, why does it not expand to x[0][0]?
During macro replacement,
A parameter in the replacement list...is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced (C++03 §16.3.1/1).
Evaluating the macro invocation, we take the following steps:
The function-like macro y is invoked with x as the argument for its arg parameter
The x in the argument is macro-replaced to become x[0]
The arg in the replacement list is replaced by the macro-replaced value of the argument, x[0]
The replacement list after substitution of all the parameters is x[0].
After all parameters in the replacement list have been substituted, the resulting preprocessing token sequence is rescanned...for more macro names to replace (C++03 §16.3.4/1).
If the name of the macro being replaced is found during this scan of the replacement list...it is not replaced. Further, if any nested replacements encounter the name of the macro being replaced, it is not replaced (C++03 §16.3.4/2).
The replacement list x[0] is rescanned (note that the name of the macro being replaced is y):
x is identified as an object-like macro invocation
x is replaced by x[0]
Replacement stops at this point because of the rule in §16.3.4/2 preventing recursion. The replacement list after rescanning is x[0][0].
I have clearly misinterpreted something since all of the preprocessors I've tested say I am wrong. In addition, this example is a piece of a larger example in the C++0x FCD (at §16.3.5/5) and it too says that the expected replacement is x[0].
Why is x not replaced during rescanning?
C99 and C++0x effectively have the same wording as C++03 in the quoted sections.