Fix bug (and add tests) for a function-like macro defined as itself.
authorCarl Worth <cworth@cworth.org>
Wed, 19 May 2010 14:29:22 +0000 (07:29 -0700)
committerCarl Worth <cworth@cworth.org>
Wed, 19 May 2010 14:29:22 +0000 (07:29 -0700)
This case worked previously, but broke in the recent rewrite of
function- like macro expansion. The recursion was still terminated
correctly, but any parenthesized expression after the macro name was
still being swallowed even though the identifier was not being
expanded as a macro.

The fix is to notice earlier that the identifier is an
already-expanding macro. We let the lexer know this through the
classify_token function so that an already-expanding macro is lexed as
an identifier, not a FUNC_MACRO.

glcpp-parse.y
tests/032-define-func-self-recurse.c [new file with mode: 0644]
tests/033-define-func-self-compose.c [new file with mode: 0644]

index 9f1075aa50a61eacd0b9ac2f7bfefa74ad225e65..8dc07483c18159f8ec168ddef1439e4610f21f36 100644 (file)
@@ -427,6 +427,22 @@ glcpp_parser_destroy (glcpp_parser_t *parser)
        talloc_free (parser);
 }
 
+static int
+glcpp_parser_is_expanding (glcpp_parser_t *parser, const char *member)
+{
+       expansion_node_t *node;
+
+       for (node = parser->expansions; node; node = node->next) {
+               if (node->macro &&
+                   strcmp (node->macro->identifier, member) == 0)
+               {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 token_class_t
 glcpp_parser_classify_token (glcpp_parser_t *parser,
                             const char *identifier,
@@ -457,6 +473,12 @@ glcpp_parser_classify_token (glcpp_parser_t *parser,
        if (macro == NULL)
                return TOKEN_CLASS_IDENTIFIER;
 
+       /* Don't consider this a macro if we are already actively
+        * expanding this macro. */
+       if (glcpp_parser_is_expanding (parser, identifier))
+               return TOKEN_CLASS_IDENTIFIER;
+
+       /* Definitely a macro. Just need to check if it's function-like. */
        if (macro->is_function)
                return TOKEN_CLASS_FUNC_MACRO;
        else
@@ -580,37 +602,6 @@ glcpp_parser_pop_expansion (glcpp_parser_t *parser)
        talloc_free (node);
 }
 
-int
-glcpp_parser_is_expanding (glcpp_parser_t *parser, const char *member)
-{
-       expansion_node_t *node;
-
-       for (node = parser->expansions; node; node = node->next) {
-               if (node->macro &&
-                   strcmp (node->macro->identifier, member) == 0)
-               {
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static void
-_expand_macro (glcpp_parser_t *parser,
-              const char *token,
-              macro_t *macro,
-              argument_list_t *arguments)
-{
-       /* Don't recurse if we're already actively expanding this token. */
-       if (glcpp_parser_is_expanding (parser, token)) {
-               printf ("%s", token);
-               return;
-       }
-
-       glcpp_parser_push_expansion_macro (parser, macro, arguments);
-}
-
 void
 _expand_object_macro (glcpp_parser_t *parser, const char *identifier)
 {
@@ -618,8 +609,9 @@ _expand_object_macro (glcpp_parser_t *parser, const char *identifier)
 
        macro = hash_table_find (parser->defines, identifier);
        assert (! macro->is_function);
+       assert (! glcpp_parser_is_expanding (parser, identifier));
 
-       _expand_macro (parser, identifier, macro, NULL);
+       glcpp_parser_push_expansion_macro (parser, macro, NULL);
 }
 
 void
@@ -631,6 +623,7 @@ _expand_function_macro (glcpp_parser_t *parser,
 
        macro = hash_table_find (parser->defines, identifier);
        assert (macro->is_function);
+       assert (! glcpp_parser_is_expanding (parser, identifier));
 
        if (_argument_list_length (arguments) !=
            _string_list_length (macro->parameters))
@@ -643,5 +636,5 @@ _expand_function_macro (glcpp_parser_t *parser,
                return;
        }
 
-       _expand_macro (parser, identifier, macro, arguments);
+       glcpp_parser_push_expansion_macro (parser, macro, arguments);
 }
diff --git a/tests/032-define-func-self-recurse.c b/tests/032-define-func-self-recurse.c
new file mode 100644 (file)
index 0000000..60d8526
--- /dev/null
@@ -0,0 +1,2 @@
+#define foo(a) foo(2 * (a))
+foo(3)
diff --git a/tests/033-define-func-self-compose.c b/tests/033-define-func-self-compose.c
new file mode 100644 (file)
index 0000000..8abaaf6
--- /dev/null
@@ -0,0 +1,2 @@
+#define foo(a) foo(2 * (a))
+foo(foo(3))