using g++ from gcc-2.96 gives precompilation errors. When trying to precompile the following lines: #define F0(arg) #define F1(arg) arg #define F2(arg) arg##1 , arg##2 #define F3(arg) F2(##arg) , arg##3 It gives the warning: warning: nothing can be pasted after this token at the last line. It looks like it cannot preprocess F2(##arg). This ends up in not being able to preprocess the rest of the source.
This is actually a warning, and a valid one. ## pasting operator shall be only used to paste two tokens together into one token, but in case of F2(##arg) there is nothing to paste in front of arg. Just remove change that into F2(arg) , arg##3 and it will be valid source.
If a formal parameter in a macro definition is preceeded or followed by the token-pasting operator, the formal parameter is immediately replaced by the unexpanded actual argument. Macro expansion is not performed on the argument prior to replacement. Check that the following lines: #define F0(arg) #define F1(arg) arg #define F2(arg) (arg1 + arg2##0) #define F3(arg1, arg2) (F2(##arg1, arg2) + 1) #define F4(arg1, arg2, narg1) F3(F##narg1(arg1), arg2) F4(1, 2, 0) are preprocessed to: (( + 20) + 1) On the other hand, if the token was expanded prior to replacement, line 4 would be illegal: (F2( , 2) +1) Note that gcc-2.95 correctly precompiles the above macros.
What standard are you mentioning here? ISO/IEC 9899:1999 6.10.3.3 states that If the result is not a valid preprocessing token, the behaviour is undefined.
The ISO/IEC 9899:1999 6.10.3.1 [#1] states: 6.10.3.1 Argument substitution [#1] After the arguments for the invocation of a function- like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), 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 as if they formed the rest of the preprocessing file; no other preprocessing tokens are available. ... The ISO/IEC 9899:1999 6.10.3.3 [#3] states that: 6.10.3.3 The ## operator ... Semantics [#2] If, in the replacement list of a function-like macro, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument's preprocessing token sequence; however, if an argument consists of no preprocessing tokens, the parameter is replaced by a placemarker preprocessing token instead.145) [#3] ... Placemarker preprocessing tokens are handled specially: concatenation of two placemarkers results in a single placemarker preprocessing token, and concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token. If the result is not a valid preprocessing token, the behavior is undefined. The resulting token is available for further macro replacement. ... I think it is pretty clear that 6.10.3.1 [#1] has higher precedence than 6.10.3.3 [#3].
Well, my reading is different. The second paragraph sais that such construct has undefined behaviour, and undefined behaviour means the preprocessor is allowed to do anything it wants, preprocess it somehow, don't preprocess it at all, start nethack. At that point the first paragraph is irrelevant I think. Probably it will be better if you argue with Zack Weinberg <zackw> and Neil Booth <neilb>, the authors of the new preprocessor.
Correction The source I wrote has one error: #define F2(arg1, arg2) (arg1 + arg2##0)
I don't understand why the second testcase was given then, because it is preprocessed with RH7 cpp as you expected (only prints out a warning that it has undefined behaviour). But current CVS gcc already will not preprocess it as you expected: $ cat XX.c #define F0(arg) #define F1(arg) arg #define F2(arg1, arg2) (arg1 + arg2##0) #define F3(arg1, arg2) (F2(##arg1, arg2) + 1) #define F4(arg1, arg2, narg1) F3(F##narg1(arg1), arg2) F4(1, 2, 0) $ gcc -E XX.c # 1 "XX.c" XX.c:4:27: warning: nothing can be pasted after this token (( + 20) + 1) $ /usr/src/gcc-2.95.2/obj/gcc/xgcc -B /usr/src/gcc-2.95.2/obj/gcc/ -E XX.c # 1 "XX.c" (( + 20) + 1) $ ./xgcc -B ./ -E XX.c # 1 "XX.c" XX.c:6:1: warning: pasting "(" and "F0" does not give a valid preprocessing token ((F0(1) + 20) + 1) $ gcc -v Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs gcc version 2.96 20000731 (Red Hat Linux 7.0) $ /usr/src/gcc-2.95.2/obj/gcc/xgcc -B /usr/src/gcc-2.95.2/obj/gcc/ -v Reading specs from /usr/src/gcc-2.95.2/obj/gcc/specs gcc version 2.95.2 19991024 (release) $ ./xgcc -B ./ -v Reading specs from ./specs Configured with: gcc version 2.97 20001205 (experimental)
This is precisely one of my points: 2.95.2 (release) does it correctly, but 2.96 and 2.97, which are development snapshots, are wrong. The second example was just to simplify the ideea. The real example I have is not compiling at all on 2.96 or 2.97, but it compiles on 2.95.2. I could send you this one, but it is quite complicated. The main features are present in the second example.
Ok, I'll say it this way, unless you convince cpp authors this is a bug in cpp (this change was intentional, btw), this will be the behaviour of gcc 3.0 and following gcc releases.