[cfe-dev] Emulation of MSVC's macro argument substitution
James Widman
widman at gimpel.com
Sun Jun 1 12:29:44 PDT 2014
On Jun 1, 2014, at 1:36 PM, Reid Kleckner <rnk at google.com> wrote:
> That's really interesting! As you guessed, though, it probably isn't a priority for me until I find some code that relies on the remaining subtle differences.
Understood. And to be clear, I’m not advocating for a change to Clang at this time; I’m just experimenting with MSVC’s behavior and documenting what I can.
It might matter to code that uses Boost.Preprocessor, however.
Here’s another example:
#define Empty
#define T() T1 Empty ()
#define T1() T2 Empty ()
#define T2() T3 Empty ()
#define T3() T4 Empty ()
#define T4() T5 Empty ()
#define T5() T6 Empty ()
#define T6() T7 Empty ()
#define T7() T8 Empty ()
#define T8() T9 Empty ()
#define T9() >>INFINITE RECURSION ERROR<<
#define A(p) p
A(T()) // ISO C/C++: T2 ()
// MSVC: >>INFINITE RECURSION ERROR<<
In this example, ISO rules indicate that the sub-sequence “T()” will be expanded twice. (Once for the “arg-as a separate file” phase, and once again, when the body of A is rescanned after parameter substitution.)
But since MSVC apparently performs two scans of a macro’s replacement list per macro invocation (one before parameter replacement and one “after”---even when there are no parameters to replace), it leads to infinite recursion.
Since I can’t use the pattern above to probe MSVC::expand(), I’m writing example templates that expand to uses of a trace-list like “T4...T0” in:
#define T0() ()
#define T1() ()
#define T2() ()
#define T3() ()
#define T4() ()
#define A(p) p
A(T4 T3 T2 T1 T0() )
// ISO: T4 T3 T2 ()
// MSVC: T4 T3 T2 ()
A(A(T4 T3 T2 T1 T0() ))
// ISO: T4 T3 ()
// MSVC: T4 T3 T2 ()
A(A(A(T4 T3 T2 T1 T0() )))
// ISO: T4 ()
// MSVC: T4 T3 T2 ()
James Widman
--
Gimpel Software
http://gimpel.com
http://twitter.com/GimpelSoftware
More information about the cfe-dev
mailing list