boostorg / wave

Boost.org wave module
http://boost.org/libs/wave
21 stars 49 forks source link

Extra space sometimes inserted after lparen in expansion of function-like macros #74

Closed jefftrull closed 4 years ago

jefftrull commented 4 years ago

If you define a function-like macro whose definition contains parenthesis, Wave will sometimes insert an extra space immediately after the left parenthesis when the macro is expanded. For example:

#define FOO(BAR, BAZ) (BAZ)
FOO("hello", 3)

becomes

( 3)

Interestingly this seems to only be true for expansion of the last parameter when there is more than one, i.e.

#define FOO(BAR, BAZ) (BAR)
FOO("hello", 3)

becomes

("hello")

and also

#define FOO(BAR) (BAR)
FOO(3)

is correctly

(3)
hkaiser commented 4 years ago

This is an interesting one!

hkaiser commented 4 years ago

@jefftrull as it turns out this behavior is by design. Wave is much more stringent wrt retaining whitespace that was passed as part of an argument for a macro invocation. Clang and gcc tend to remove whitespace that is not needed for syntactic disambiguation. Assuming:

#define FOO1(BAR, BAZ) (BAR)
#define FOO2(BAR, BAZ) (BAZ)

we get

FOO2("hello", 3)       // expands to ( 3)
FOO2("hello",    3)    // expands to (    3)
FOO2("hello",3)        // expands to (3)

(please note the additional whitespace in front of the argument 3).

That said however, while investigating this issue I noticed that wave removes whitespace following the last argument:

FOO1( "hello" , 3 )    // expands to ( "hello" ) as it should
FOO2( "hello" , 3 )    // expands to ( 3) but should expand to ( 3 )

I think this is something that needs a fix.

jefftrull commented 4 years ago

Thanks for the explanation!

Interestingly, I cannot duplicate your finding that the final space is removed. The output for me is:

    ( "hello" ); 
    ( 3 ); 
jefftrull commented 4 years ago

For future readers, the behavior of gcc is described at the bottom of page 15 on this document:

Leading and trailing whitespace in each argument is dropped, and all whitespace between the tokens of an argument is reduced to a single space.

hkaiser commented 4 years ago

Interestingly, I cannot duplicate your finding that the final space is removed. The output for me is: ( "hello" ); ( 3 );

Yes, I agree. I'm not sure what I was looking at anymore :/ I think we can close this for now.