add support for gcc nested functions
[cparser] / parser.c
index c4523d8..77c5884 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -555,6 +555,7 @@ static void restore_anchor_state(int token_type, int count)
 static void rem_anchor_token(int token_type)
 {
        assert(0 <= token_type && token_type < T_LAST_TOKEN);
+       assert(token_anchor_set[token_type] != 0);
        --token_anchor_set[token_type];
 }
 
@@ -642,16 +643,6 @@ static void eat_block(void)
                next_token();
 }
 
-/**
- * eat all token until a ';' is reached or a stop token is found.
- */
-static void eat_statement(void)
-{
-       eat_until_matching_token(';');
-       if (token.type == ';')
-               next_token();
-}
-
 #define eat(token_type)  do { assert(token.type == token_type); next_token(); } while (0)
 
 /**
@@ -696,18 +687,18 @@ static void type_error_incompatible(const char *msg,
  * If not, generate an error, eat the current statement,
  * and goto the end_error label.
  */
-#define expect(expected)                              \
-       do {                                              \
-    if (UNLIKELY(token.type != (expected))) {          \
-        parse_error_expected(NULL, (expected), NULL); \
-               add_anchor_token(expected);                   \
-        eat_until_anchor();                           \
-        if (token.type == expected)                   \
-               next_token();                             \
-               rem_anchor_token(expected);                   \
-        goto end_error;                               \
-    }                                                 \
-    next_token();                                     \
+#define expect(expected)                                  \
+       do {                                                  \
+               if (UNLIKELY(token.type != (expected))) {         \
+                       parse_error_expected(NULL, (expected), NULL); \
+                       add_anchor_token(expected);                   \
+                       eat_until_anchor();                           \
+                       if (token.type == expected)                   \
+                               next_token();                             \
+                       rem_anchor_token(expected);                   \
+                       goto end_error;                               \
+               }                                                 \
+               next_token();                                     \
        } while (0)
 
 static void set_scope(scope_t *new_scope)
@@ -1500,12 +1491,12 @@ static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
        add_anchor_token(',');
        parse_constant_expression();
        rem_anchor_token(',');
-       rem_anchor_token('(');
+       rem_anchor_token(')');
 
        expect(',');
        add_anchor_token(')');
        parse_constant_expression();
-       rem_anchor_token('(');
+       rem_anchor_token(')');
        expect(')');
        return;
 end_error:
@@ -2474,6 +2465,10 @@ finish_designator:
 
                        if (type == NULL) {
                                /* we are already outside, ... */
+                               if (is_type_compound(outer_type) &&
+                                   !outer_type->compound.declaration->init.complete) {
+                                       goto error_parse_next;
+                               }
                                goto error_excess;
                        }
 
@@ -2697,6 +2692,7 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                                errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)",
                                       is_struct ? "struct" : "union", symbol,
                                       &declaration->source_position);
+                               declaration->scope.declarations = NULL;
                        }
                }
        } else if (token.type != '{') {
@@ -2711,17 +2707,18 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                return NULL;
        }
 
-       /* always create a new declaration, do NOT modify old one */
-       declaration = allocate_declaration_zero();
-       declaration->namespc         =
-               (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
-       declaration->source_position = token.source_position;
-       declaration->symbol          = symbol;
-       declaration->parent_scope    = scope;
-       if (symbol != NULL) {
-               environment_push(declaration);
+       if (declaration == NULL) {
+               declaration = allocate_declaration_zero();
+               declaration->namespc         =
+                       (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
+               declaration->source_position = token.source_position;
+               declaration->symbol          = symbol;
+               declaration->parent_scope    = scope;
+               if (symbol != NULL) {
+                       environment_push(declaration);
+               }
+               append_declaration(declaration);
        }
-       append_declaration(declaration);
 
        if (token.type == '{') {
                declaration->init.complete = true;
@@ -2784,14 +2781,11 @@ end_error:
        ;
 }
 
-/**
- * Parse enum specifier and return the enum type or NULL on error.
- */
 static type_t *parse_enum_specifier(void)
 {
-       gnu_attribute_t *attributes  = NULL;
-       declaration_t   *declaration = NULL;
-       symbol_t        *symbol      = NULL;
+       gnu_attribute_t *attributes = NULL;
+       declaration_t   *declaration;
+       symbol_t        *symbol;
 
        eat(T_enum);
        if (token.type == T_IDENTIFIER) {
@@ -2803,31 +2797,30 @@ static type_t *parse_enum_specifier(void)
                parse_error_expected("while parsing enum type specifier",
                                     T_IDENTIFIER, '{', NULL);
                return NULL;
+       } else {
+               declaration = NULL;
+               symbol      = NULL;
        }
 
-       if (token.type == '{' && declaration != NULL && declaration->init.complete) {
-               errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)",
-                       symbol, &declaration->source_position);
-       }
-
-       declaration = allocate_declaration_zero();
-       declaration->namespc         = NAMESPACE_ENUM;
-       declaration->source_position = token.source_position;
-       declaration->symbol          = symbol;
-       declaration->parent_scope    = scope;
-       if (symbol != NULL) {
-               environment_push(declaration);
+       if (declaration == NULL) {
+               declaration = allocate_declaration_zero();
+               declaration->namespc         = NAMESPACE_ENUM;
+               declaration->source_position = token.source_position;
+               declaration->symbol          = symbol;
+               declaration->parent_scope  = scope;
        }
-       append_declaration(declaration);
 
        type_t *const type      = allocate_type_zero(TYPE_ENUM, &declaration->source_position);
        type->enumt.declaration = declaration;
 
        if (token.type == '{') {
                if (declaration->init.complete) {
-                       errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)",
-                              symbol, &declaration->source_position);
+                       errorf(HERE, "multiple definitions of enum %Y", symbol);
                }
+               if (symbol != NULL) {
+                       environment_push(declaration);
+               }
+               append_declaration(declaration);
                declaration->init.complete = true;
 
                parse_enum_entries(type);
@@ -3585,10 +3578,8 @@ warn_about_long_long:
                default:
                        /* invalid specifier combination, give an error message */
                        if (type_specifiers == 0) {
-                               if (saw_error) {
-                                       specifiers->type = type_error_type;
-                                       return;
-                               }
+                               if (saw_error)
+                                       goto end_error;
 
                                if (!strict_mode) {
                                        if (warning.implicit_int) {
@@ -3607,15 +3598,13 @@ warn_about_long_long:
                        } else {
                                errorf(HERE, "multiple datatypes in declaration");
                        }
-                       atomic_type = ATOMIC_TYPE_INVALID;
+                       goto end_error;
                }
 
-               if (type_specifiers & SPECIFIER_COMPLEX &&
-                  atomic_type != ATOMIC_TYPE_INVALID) {
+               if (type_specifiers & SPECIFIER_COMPLEX) {
                        type                = allocate_type_zero(TYPE_COMPLEX, &builtin_source_position);
                        type->complex.akind = atomic_type;
-               } else if (type_specifiers & SPECIFIER_IMAGINARY &&
-                         atomic_type != ATOMIC_TYPE_INVALID) {
+               } else if (type_specifiers & SPECIFIER_IMAGINARY) {
                        type                  = allocate_type_zero(TYPE_IMAGINARY, &builtin_source_position);
                        type->imaginary.akind = atomic_type;
                } else {
@@ -3638,7 +3627,10 @@ warn_about_long_long:
        }
 
        specifiers->type = result;
+       return;
+
 end_error:
+       specifiers->type = type_error_type;
        return;
 }
 
@@ -3912,9 +3904,8 @@ static construct_type_t *parse_array_declarator(void)
        rem_anchor_token(']');
        expect(']');
 
-       return (construct_type_t*) array;
 end_error:
-       return NULL;
+       return (construct_type_t*) array;
 }
 
 static construct_type_t *parse_function_declarator(declaration_t *declaration)
@@ -4053,13 +4044,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
                if (may_be_abstract)
                        break;
                parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
-               /* avoid a loop in the outermost scope, because eat_statement doesn't
-                * eat '}' */
-               if (token.type == '}' && current_function == NULL) {
-                       next_token();
-               } else {
-                       eat_statement();
-               }
+               eat_until_anchor();
                return NULL;
        }
 
@@ -4158,15 +4143,19 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        function_type->function.return_type = type;
 
                        type_t *skipped_return_type = skip_typeref(type);
+                       /* §6.7.5.3(1) */
                        if (is_type_function(skipped_return_type)) {
                                errorf(HERE, "function returning function is not allowed");
-                               type = type_error_type;
                        } else if (is_type_array(skipped_return_type)) {
                                errorf(HERE, "function returning array is not allowed");
-                               type = type_error_type;
                        } else {
-                               type = function_type;
+                               if (skipped_return_type->base.qualifiers != 0) {
+                                       warningf(HERE,
+                                               "type qualifiers in return type of function type are meaningless");
+                               }
                        }
+
+                       type = function_type;
                        break;
                }
 
@@ -4207,12 +4196,13 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        }
 
                        type_t *skipped_type = skip_typeref(type);
-                       if (is_type_atomic(skipped_type, ATOMIC_TYPE_VOID)) {
-                               errorf(HERE, "array of void is not allowed");
-                               type = type_error_type;
-                       } else {
-                               type = array_type;
+                       /* §6.7.5.2(1) */
+                       if (is_type_incomplete(skipped_type)) {
+                               errorf(HERE, "array of incomplete type '%T' is not allowed", type);
+                       } else if (is_type_function(skipped_type)) {
+                               errorf(HERE, "array of functions is not allowed");
                        }
+                       type = array_type;
                        break;
                }
                }
@@ -4309,7 +4299,7 @@ static void check_type_of_main(const declaration_t *const decl, const function_t
                warningf(&decl->source_position,
                         "'main' is normally a non-static function");
        }
-       if (skip_typeref(func_type->return_type) != type_int) {
+       if (!types_compatible(skip_typeref(func_type->return_type), type_int)) {
                warningf(&decl->source_position,
                         "return type of 'main' should be 'int', but is '%T'",
                         func_type->return_type);
@@ -4372,7 +4362,7 @@ static declaration_t *record_declaration(
                        previous_declaration == NULL) {
                warningf(&declaration->source_position,
                         "function declaration '%#T' is not a prototype",
-                        orig_type, declaration->symbol);
+                        orig_type, symbol);
        }
 
        if (warning.main && is_type_function(type) && is_sym_main(symbol)) {
@@ -4605,18 +4595,9 @@ static void parse_anonymous_declaration_rest(
 
        if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) {
                warningf(&specifiers->source_position,
-                       "useless storage class in empty declaration");
+                        "useless storage class in empty declaration");
        }
 
-#ifdef RECORD_EMPTY_DECLARARTIONS
-       declaration_t *const declaration    = allocate_declaration_zero();
-       declaration->type                   = specifiers->type;
-       declaration->declared_storage_class = specifiers->declared_storage_class;
-       declaration->source_position        = specifiers->source_position;
-       declaration->modifiers              = specifiers->modifiers;
-       declaration->storage_class          = STORAGE_CLASS_NONE;
-#endif
-
        type_t *type = specifiers->type;
        switch (type->kind) {
                case TYPE_COMPOUND_STRUCT:
@@ -4636,7 +4617,14 @@ static void parse_anonymous_declaration_rest(
                        break;
        }
 
-#ifdef RECORD_EMPTY_DECLARARTIONS
+#ifdef RECORD_EMPTY_DECLARATIONS
+       declaration_t *const declaration    = allocate_declaration_zero();
+       declaration->type                   = specifiers->type;
+       declaration->declared_storage_class = specifiers->declared_storage_class;
+       declaration->source_position        = specifiers->source_position;
+       declaration->modifiers              = specifiers->modifiers;
+       declaration->storage_class          = STORAGE_CLASS_NONE;
+
        append_declaration(declaration);
 #endif
 }
@@ -4719,7 +4707,10 @@ static void parse_declaration(parsed_declaration_func finished_declaration)
 {
        declaration_specifiers_t specifiers;
        memset(&specifiers, 0, sizeof(specifiers));
+
+       add_anchor_token(';');
        parse_declaration_specifiers(&specifiers);
+       rem_anchor_token(';');
 
        if (token.type == ';') {
                parse_anonymous_declaration_rest(&specifiers);
@@ -5389,7 +5380,7 @@ static void parse_external_declaration(void)
 
        add_anchor_token(',');
        add_anchor_token('=');
-       rem_anchor_token(';');
+       add_anchor_token(';');
 
        /* declarator is common to both function-definitions and declarations */
        declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
@@ -6208,11 +6199,12 @@ static expression_t *parse_compound_literal(type_t *type)
  */
 static expression_t *parse_cast(void)
 {
+       add_anchor_token(')');
+
        source_position_t source_position = token.source_position;
 
        type_t *type  = parse_typename();
 
-       /* matching add_anchor_token() is at call site */
        rem_anchor_token(')');
        expect(')');
 
@@ -6241,6 +6233,8 @@ end_error:
  */
 static expression_t *parse_statement_expression(void)
 {
+       add_anchor_token(')');
+
        expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
 
        statement_t *statement           = parse_compound_statement(true);
@@ -6262,11 +6256,11 @@ static expression_t *parse_statement_expression(void)
        }
        expression->base.type = type;
 
+       rem_anchor_token(')');
        expect(')');
 
-       return expression;
 end_error:
-       return create_invalid_expression();
+       return expression;
 }
 
 /**
@@ -6275,7 +6269,6 @@ end_error:
 static expression_t *parse_parenthesized_expression(void)
 {
        eat('(');
-       add_anchor_token(')');
 
        switch(token.type) {
        case '{':
@@ -6291,13 +6284,13 @@ static expression_t *parse_parenthesized_expression(void)
                }
        }
 
+       add_anchor_token(')');
        expression_t *result = parse_expression();
        rem_anchor_token(')');
        expect(')');
 
-       return result;
 end_error:
-       return create_invalid_expression();
+       return result;
 }
 
 static expression_t *parse_function_keyword(void)
@@ -6474,17 +6467,15 @@ static expression_t *parse_va_start(void)
        expression_t *const expr = parse_assignment_expression();
        if (expr->kind == EXPR_REFERENCE) {
                declaration_t *const decl = expr->reference.declaration;
-               if (decl == NULL)
-                       return create_invalid_expression();
-               if (decl->parent_scope == &current_function->scope &&
-                   decl->next == NULL) {
-                       expression->va_starte.parameter = decl;
-                       expect(')');
-                       return expression;
+               if (decl->parent_scope != &current_function->scope || decl->next != NULL) {
+                       errorf(&expr->base.source_position,
+                              "second argument of 'va_start' must be last parameter of the current function");
                }
+               expression->va_starte.parameter = decl;
+               expect(')');
+               return expression;
        }
-       errorf(&expr->base.source_position,
-              "second argument of 'va_start' must be last parameter of the current function");
+       expect(')');
 end_error:
        return create_invalid_expression();
 }
@@ -6908,12 +6899,16 @@ static expression_t *parse_typeprop(expression_kind_t const kind,
                                     source_position_t const pos,
                                     unsigned const precedence)
 {
-       expression_t *tp_expression = allocate_expression_zero(kind);
+       expression_t  *tp_expression = allocate_expression_zero(kind);
        tp_expression->base.type            = type_size_t;
        tp_expression->base.source_position = pos;
 
        char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
 
+       /* we only refer to a type property, not the value, so do not warn
+        * when using current_init_decl */
+       declaration_t *old = current_init_decl;
+       current_init_decl  = NULL;
        if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
                next_token();
                add_anchor_token(')');
@@ -6953,9 +6948,9 @@ static expression_t *parse_typeprop(expression_kind_t const kind,
                tp_expression->typeprop.tp_expression = expression;
        }
 
-       return tp_expression;
 end_error:
-       return create_invalid_expression();
+       current_init_decl  = old;
+       return tp_expression;
 }
 
 static expression_t *parse_sizeof(unsigned precedence)
@@ -7211,9 +7206,8 @@ static expression_t *parse_call_expression(unsigned precedence,
                         "function call has aggregate value");
        }
 
-       return result;
 end_error:
-       return create_invalid_expression();
+       return result;
 }
 
 static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right);
@@ -9154,7 +9148,7 @@ static statement_t *parse_goto(void)
                                parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
                        else
                                parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
-                       eat_statement();
+                       eat_until_anchor();
                        goto end_error;
                }
                symbol_t *symbol = token.v.symbol;
@@ -9362,7 +9356,10 @@ static statement_t *parse_declaration_statement(void)
        statement->base.source_position = token.source_position;
 
        declaration_t *before = last_declaration;
-       parse_declaration(record_declaration);
+       if (c_mode & _GNUC)
+               parse_external_declaration();
+       else
+               parse_declaration(record_declaration);
 
        if (before == NULL) {
                statement->declaration.declarations_begin = scope->declarations;
@@ -9553,7 +9550,7 @@ expression_statment:
 
        case ';':        statement = parse_empty_statement();         break;
        case '{':        statement = parse_compound_statement(false); break;
-       case T___leave:  statement = parse_leave_statement();                   break;
+       case T___leave:  statement = parse_leave_statement();         break;
        case T___try:    statement = parse_ms_try_statment();         break;
        case T_asm:      statement = parse_asm_statement();           break;
        case T_break:    statement = parse_break();                   break;
@@ -9567,7 +9564,58 @@ expression_statment:
        case T_return:   statement = parse_return();                  break;
        case T_switch:   statement = parse_switch();                  break;
        case T_while:    statement = parse_while();                   break;
-       default:         statement = parse_expression_statement();    break;
+
+       case '!':
+       case '&':
+       case '(':
+       case '*':
+       case '+':
+       case '-':
+       case '~':
+       case T_ANDAND:
+       case T_CHARACTER_CONSTANT:
+       case T_FLOATINGPOINT:
+       case T_INTEGER:
+       case T_MINUSMINUS:
+       case T_PLUSPLUS:
+       case T_STRING_LITERAL:
+       case T_WIDE_CHARACTER_CONSTANT:
+       case T_WIDE_STRING_LITERAL:
+       case T___FUNCDNAME__:
+       case T___FUNCSIG__:
+       case T___FUNCTION__:
+       case T___PRETTY_FUNCTION__:
+       case T___builtin_alloca:
+       case T___builtin_classify_type:
+       case T___builtin_constant_p:
+       case T___builtin_expect:
+       case T___builtin_huge_val:
+       case T___builtin_isgreater:
+       case T___builtin_isgreaterequal:
+       case T___builtin_isless:
+       case T___builtin_islessequal:
+       case T___builtin_islessgreater:
+       case T___builtin_isunordered:
+       case T___builtin_nan:
+       case T___builtin_nand:
+       case T___builtin_nanf:
+       case T___builtin_offsetof:
+       case T___builtin_prefetch:
+       case T___builtin_va_arg:
+       case T___builtin_va_end:
+       case T___builtin_va_start:
+       case T___func__:
+       case T___noop:
+       case T__assume:
+               statement = parse_expression_statement();
+               break;
+
+       default:
+               errorf(HERE, "unexpected token %K while parsing statement", &token);
+               statement = create_invalid_statement();
+               if (!at_anchor())
+                       next_token();
+               break;
        }
        rem_anchor_token(';');
 
@@ -9764,32 +9812,47 @@ end_error:;
  */
 static void parse_translation_unit(void)
 {
-       for (;;) switch (token.type) {
-               DECLARATION_START
-               case T_IDENTIFIER:
-               case T___extension__:
-                       parse_external_declaration();
-                       break;
+       for (;;) {
+#ifndef NDEBUG
+               bool anchor_leak = false;
+               for (token_type_t i = 0; i != T_LAST_TOKEN; ++i) {
+                       unsigned char count = token_anchor_set[i];
+                       if (count != 0) {
+                               errorf(HERE, "Leaked anchor token %k %d times", i, count);
+                               anchor_leak = true;
+                       }
+               }
+               if (anchor_leak)
+                       abort();
+#endif
 
-               case T_asm:
-                       parse_global_asm();
-                       break;
+               switch (token.type) {
+                       DECLARATION_START
+                       case T_IDENTIFIER:
+                       case T___extension__:
+                               parse_external_declaration();
+                               break;
 
-               case T_EOF:
-                       return;
+                       case T_asm:
+                               parse_global_asm();
+                               break;
 
-               case ';':
-                       /* TODO error in strict mode */
-                       warningf(HERE, "stray ';' outside of function");
-                       next_token();
-                       break;
+                       case T_EOF:
+                               return;
 
-               default:
-                       errorf(HERE, "stray %K outside of function", &token);
-                       if (token.type == '(' || token.type == '{' || token.type == '[')
-                               eat_until_matching_token(token.type);
-                       next_token();
-                       break;
+                       case ';':
+                               /* TODO error in strict mode */
+                               warningf(HERE, "stray ';' outside of function");
+                               next_token();
+                               break;
+
+                       default:
+                               errorf(HERE, "stray %K outside of function", &token);
+                               if (token.type == '(' || token.type == '{' || token.type == '[')
+                                       eat_until_matching_token(token.type);
+                               next_token();
+                               break;
+               }
        }
 }