Arg substitution leaves placeholder marker in the stream for empty arguments. Those need to be skipped when searching for a fnlike macro invocation in the replacement list itself. See testcase.
Unified · Split
| @@ -3023,7 +3023,7 @@ static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *w · 3022 unmodified lines | |||
| 3023 | if (macro_ptr) { | 3023 | if (macro_ptr) { |
| 3024 | p = macro_ptr, t = *p; | 3024 | p = macro_ptr, t = *p; |
| 3025 | if (ws_str) { | 3025 | if (ws_str) { |
| 3026 | while (is_space(t) || TOK_LINEFEED == t) | 3026 | while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t) |
| 3027 | tok_str_add(ws_str, t), t = *++p; | 3027 | tok_str_add(ws_str, t), t = *++p; |
| 3028 | } | 3028 | } |
| 3029 | if (t == 0 && can_read_stream) { | 3029 | if (t == 0 && can_read_stream) { |
| @@ -3152,7 +3152,9 @@ static int macro_subst_tok( · 122 unmodified lines | |||
| 3152 | } else { | 3152 | } else { |
| 3153 | tok_str_free_str(ws_str.str); | 3153 | tok_str_free_str(ws_str.str); |
| 3154 | } | 3154 | } |
| 3155 | next_nomacro(); /* eat '(' */ | 3155 | do { |
| 3156 | next_nomacro(); /* eat '(' */ | ||
| 3157 | } while (tok == TOK_PLCHLDR); | ||
| 3156 | 3158 | ||
| 3157 | /* argument macro */ | 3159 | /* argument macro */ |
| 3158 | args = NULL; | 3160 | args = NULL; |
| @@ -0,0 +1,15 @@ | |||
| 1 | #define M_RETI_ARG27(x,y,z,aa, ...) aa | ||
| 2 | #define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__) | ||
| 3 | #define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 0, useless) | ||
| 4 | #define M_EMPTYI_DETECT(...) 0, 1, | ||
| 5 | #define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ () ) | ||
| 6 | #define EX | ||
| 7 | #define empty(x) | ||
| 8 | #define fnlike(x) yeah x | ||
| 9 | /* If the following macro is called with empty arg (X183), the use | ||
| 10 | of 'x' between fnlike and '(' doesn't hinder the recognition of this | ||
| 11 | being a further fnlike macro invocation. */ | ||
| 12 | #define usefnlike(x) fnlike x (x) | ||
| 13 | X181 M_EMPTYI_P_C1() | ||
| 14 | X182 M_EMPTYI_P_C1(x) | ||
| 15 | X183 usefnlike() | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | X181 1 | ||
| 2 | X182 0 | ||
| 3 | X183 yeah | ||