[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