Ooops, streq is the right function here.
[cparser] / parser.c
index f14a3f1..3c5383b 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -111,10 +111,26 @@ static declaration_t      **incomplete_arrays;
 static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 
 
-#define PUSH_PARENT(stmt)                          \
-       statement_t *const prev_parent = current_parent; \
-       ((void)(current_parent = (stmt)))
-#define POP_PARENT ((void)(current_parent = prev_parent))
+#define PUSH_PARENT(stmt) \
+       statement_t *const new_parent = (stmt); \
+       statement_t *const old_parent = current_parent; \
+       ((void)(current_parent = new_parent))
+#define POP_PARENT() (assert(current_parent == new_parent), (void)(current_parent = old_parent))
+
+#define PUSH_SCOPE(scope) \
+       size_t   const top       = environment_top(); \
+       scope_t *const new_scope = (scope); \
+       scope_t *const old_scope = scope_push(new_scope)
+#define POP_SCOPE() (assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top))
+
+#define PUSH_EXTENSION() \
+       bool const old_gcc_extension = in_gcc_extension; \
+       while (next_if(T___extension__)) { \
+               in_gcc_extension = true; \
+       } \
+       do {} while (0)
+#define POP_EXTENSION() \
+       ((void)(in_gcc_extension = old_gcc_extension))
 
 /** special symbol used for anonymous entities. */
 static symbol_t *sym_anonymous = NULL;
@@ -655,9 +671,9 @@ static void type_error_incompatible(const char *msg,
                        parse_error_expected(NULL, (expected), NULL); \
                        add_anchor_token(expected);                   \
                        eat_until_anchor();                           \
-                       next_if((expected));                          \
                        rem_anchor_token(expected);                   \
-                       goto error_label;                             \
+                       if (token.type != (expected))                 \
+                         goto error_label;                           \
                }                                                 \
                next_token();                                     \
        } while (0)
@@ -1102,7 +1118,8 @@ static int strcmp_underscore(const char *s1, const char *s2)
 static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
 {
        attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
-       attribute->kind        = kind;
+       attribute->kind            = kind;
+       attribute->source_position = *HERE;
        return attribute;
 }
 
@@ -1171,9 +1188,8 @@ end_error:
 
 static attribute_t *parse_attribute_asm(void)
 {
-       eat(T_asm);
-
        attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
+       eat(T_asm);
 
        expect('(', end_error);
        attribute->a.arguments = parse_attribute_arguments();
@@ -1248,9 +1264,8 @@ static attribute_t *parse_attribute_gnu_single(void)
                        break;
        }
 
-       next_token();
-
        attribute_t *attribute = allocate_attribute_zero(kind);
+       next_token();
 
        /* parse arguments */
        if (next_if('('))
@@ -1304,30 +1319,30 @@ static attribute_t *parse_attributes(attribute_t *first)
                        break;
 
                case T_cdecl:
-                       next_token();
                        attribute = allocate_attribute_zero(ATTRIBUTE_MS_CDECL);
+                       eat(T_cdecl);
                        break;
 
                case T__fastcall:
-                       next_token();
                        attribute = allocate_attribute_zero(ATTRIBUTE_MS_FASTCALL);
+                       eat(T__fastcall);
                        break;
 
                case T__forceinline:
-                       next_token();
                        attribute = allocate_attribute_zero(ATTRIBUTE_MS_FORCEINLINE);
+                       eat(T__forceinline);
                        break;
 
                case T__stdcall:
-                       next_token();
                        attribute = allocate_attribute_zero(ATTRIBUTE_MS_STDCALL);
+                       eat(T__stdcall);
                        break;
 
                case T___thiscall:
                        /* TODO record modifier */
                        warningf(WARN_OTHER, HERE, "Ignoring declaration modifier %K", &token);
-                       eat(T___thiscall);
                        attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL);
+                       eat(T___thiscall);
                        break;
 
                default:
@@ -2568,14 +2583,9 @@ static type_t *parse_typeof(void)
 
        expression_t *expression  = NULL;
 
-       bool old_type_prop     = in_type_prop;
-       bool old_gcc_extension = in_gcc_extension;
-       in_type_prop           = true;
+       bool old_type_prop = in_type_prop;
+       in_type_prop       = true;
 
-       while (next_if(T___extension__)) {
-               /* This can be a prefix to a typename or an expression. */
-               in_gcc_extension = true;
-       }
        switch (token.type) {
        case T_IDENTIFIER:
                if (is_typedef_symbol(token.symbol)) {
@@ -2588,8 +2598,7 @@ static type_t *parse_typeof(void)
                }
                break;
        }
-       in_type_prop     = old_type_prop;
-       in_gcc_extension = old_gcc_extension;
+       in_type_prop = old_type_prop;
 
        rem_anchor_token(')');
        expect(')', end_error);
@@ -2700,13 +2709,13 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
                if (kind == ATTRIBUTE_UNKNOWN) {
                        warningf(WARN_ATTRIBUTE, HERE, "unknown __declspec '%s' ignored", name);
                }
-               eat(T_IDENTIFIER);
        } else {
                parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL);
                return NULL;
        }
 
        attribute_t *attribute = allocate_attribute_zero(kind);
+       eat(T_IDENTIFIER);
 
        if (kind == ATTRIBUTE_MS_PROPERTY) {
                return parse_attribute_ms_property(attribute);
@@ -2771,12 +2780,11 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
 
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
-       type_t            *type              = NULL;
-       type_qualifiers_t  qualifiers        = TYPE_QUALIFIER_NONE;
-       unsigned           type_specifiers   = 0;
-       bool               newtype           = false;
-       bool               saw_error         = false;
-       bool               old_gcc_extension = in_gcc_extension;
+       type_t            *type            = NULL;
+       type_qualifiers_t  qualifiers      = TYPE_QUALIFIER_NONE;
+       unsigned           type_specifiers = 0;
+       bool               newtype         = false;
+       bool               saw_error       = false;
 
        memset(specifiers, 0, sizeof(*specifiers));
        specifiers->source_position = token.source_position;
@@ -2848,11 +2856,6 @@ wrong_thread_storage_class:
                MATCH_TYPE_QUALIFIER(T___uptr,   TYPE_QUALIFIER_UPTR);
                MATCH_TYPE_QUALIFIER(T___sptr,   TYPE_QUALIFIER_SPTR);
 
-               case T___extension__:
-                       next_token();
-                       in_gcc_extension = true;
-                       break;
-
                /* type specifiers */
 #define MATCH_SPECIFIER(token, specifier, name)                         \
                case token:                                                     \
@@ -3003,8 +3006,6 @@ wrong_thread_storage_class:
 finish_specifiers:
        specifiers->attributes = parse_attributes(specifiers->attributes);
 
-       in_gcc_extension = old_gcc_extension;
-
        if (type == NULL || (saw_error && type_specifiers != 0)) {
                atomic_type_kind_t atomic_type;
 
@@ -3317,7 +3318,6 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                                goto parameters_finished;
 
                        case T_IDENTIFIER:
-                       case T___extension__:
                        DECLARATION_START
                        {
                                entity_t *entity = parse_parameter();
@@ -4529,9 +4529,7 @@ static void parse_kr_declaration_list(entity_t *entity)
 
        add_anchor_token('{');
 
-       /* push function parameters */
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&entity->function.parameters);
+       PUSH_SCOPE(&entity->function.parameters);
 
        entity_t *parameter = entity->function.parameters.entities;
        for ( ; parameter != NULL; parameter = parameter->base.next) {
@@ -4544,7 +4542,6 @@ static void parse_kr_declaration_list(entity_t *entity)
        for (;;) {
                switch (token.type) {
                        DECLARATION_START
-                       case T___extension__:
                        /* This covers symbols, which are no type, too, and results in
                         * better error messages.  The typical cases are misspelled type
                         * names and missing includes. */
@@ -4557,10 +4554,7 @@ static void parse_kr_declaration_list(entity_t *entity)
        }
 decl_list_end:
 
-       /* pop function parameters */
-       assert(current_scope == &entity->function.parameters);
-       scope_pop(old_scope);
-       environment_pop_to(top);
+       POP_SCOPE();
 
        /* update function type */
        type_t *new_type = duplicate_type(type);
@@ -5463,9 +5457,7 @@ static void parse_external_declaration(void)
        assert(is_declaration(entity));
        type = skip_typeref(entity->declaration.type);
 
-       /* push function parameters and switch scope */
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&function->parameters);
+       PUSH_SCOPE(&function->parameters);
 
        entity_t *parameter = function->parameters.entities;
        for (; parameter != NULL; parameter = parameter->base.next) {
@@ -5492,7 +5484,7 @@ static void parse_external_declaration(void)
                entity_t   *old_current_entity   = current_entity;
                current_function                 = function;
                current_entity                   = entity;
-               current_parent                   = NULL;
+               PUSH_PARENT(NULL);
 
                goto_first   = NULL;
                goto_anchor  = &goto_first;
@@ -5518,7 +5510,7 @@ static void parse_external_declaration(void)
                        }
                }
 
-               assert(current_parent   == NULL);
+               POP_PARENT();
                assert(current_function == function);
                assert(current_entity   == entity);
                current_entity   = old_current_entity;
@@ -5526,9 +5518,7 @@ static void parse_external_declaration(void)
                label_pop_to(label_stack_top);
        }
 
-       assert(current_scope == &function->parameters);
-       scope_pop(old_scope);
-       environment_pop_to(top);
+       POP_SCOPE();
 }
 
 static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
@@ -5774,20 +5764,28 @@ static void parse_compound_type_entries(compound_t *compound)
        eat('{');
        add_anchor_token('}');
 
-       while (token.type != '}') {
-               if (token.type == T_EOF) {
-                       errorf(HERE, "EOF while parsing struct");
-                       break;
+       for (;;) {
+               switch (token.type) {
+                       DECLARATION_START
+                       case T___extension__:
+                       case T_IDENTIFIER: {
+                               PUSH_EXTENSION();
+                               declaration_specifiers_t specifiers;
+                               parse_declaration_specifiers(&specifiers);
+                               parse_compound_declarators(compound, &specifiers);
+                               POP_EXTENSION();
+                               break;
+                       }
+
+                       default:
+                               rem_anchor_token('}');
+                               expect('}', end_error);
+end_error:
+                               /* §6.7.2.1:7 */
+                               compound->complete = true;
+                               return;
                }
-               declaration_specifiers_t specifiers;
-               parse_declaration_specifiers(&specifiers);
-               parse_compound_declarators(compound, &specifiers);
        }
-       rem_anchor_token('}');
-       next_token();
-
-       /* §6.7.2.1:7 */
-       compound->complete = true;
 }
 
 static type_t *parse_typename(void)
@@ -5884,10 +5882,9 @@ static expression_t *parse_string_literal(void)
 static expression_t *parse_boolean_literal(bool value)
 {
        expression_t *literal = allocate_expression_zero(EXPR_LITERAL_BOOLEAN);
-       literal->base.source_position = token.source_position;
-       literal->base.type            = type_bool;
-       literal->literal.value.begin  = value ? "true" : "false";
-       literal->literal.value.size   = value ? 4 : 5;
+       literal->base.type           = type_bool;
+       literal->literal.value.begin = value ? "true" : "false";
+       literal->literal.value.size  = value ? 4 : 5;
 
        next_token();
        return literal;
@@ -5999,10 +5996,9 @@ static expression_t *parse_number_literal(void)
        }
 
        expression_t *literal = allocate_expression_zero(kind);
-       literal->base.source_position = token.source_position;
-       literal->base.type            = type;
-       literal->literal.value        = token.literal;
-       literal->literal.suffix       = token.symbol;
+       literal->base.type      = type;
+       literal->literal.value  = token.literal;
+       literal->literal.suffix = token.symbol;
        next_token();
 
        /* integer type depends on the size of the number and the size
@@ -6019,9 +6015,8 @@ static expression_t *parse_number_literal(void)
 static expression_t *parse_character_constant(void)
 {
        expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
-       literal->base.source_position = token.source_position;
-       literal->base.type            = c_mode & _CXX ? type_char : type_int;
-       literal->literal.value        = token.literal;
+       literal->base.type     = c_mode & _CXX ? type_char : type_int;
+       literal->literal.value = token.literal;
 
        size_t len = literal->literal.value.size;
        if (len > 1) {
@@ -6043,9 +6038,8 @@ static expression_t *parse_character_constant(void)
 static expression_t *parse_wide_character_constant(void)
 {
        expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
-       literal->base.source_position = token.source_position;
-       literal->base.type            = type_int;
-       literal->literal.value        = token.literal;
+       literal->base.type     = type_int;
+       literal->literal.value = token.literal;
 
        size_t len = wstrlen(&literal->literal.value);
        if (len > 1) {
@@ -6344,9 +6338,10 @@ static bool semantic_cast(expression_t *cast)
        return true;
 }
 
-static expression_t *parse_compound_literal(type_t *type)
+static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type)
 {
        expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
+       expression->base.source_position = *pos;
 
        parse_initializer_env_t env;
        env.type             = type;
@@ -6367,7 +6362,7 @@ static expression_t *parse_compound_literal(type_t *type)
  */
 static expression_t *parse_cast(void)
 {
-       source_position_t source_position = token.source_position;
+       source_position_t const pos = *HERE;
 
        eat('(');
        add_anchor_token(')');
@@ -6378,11 +6373,11 @@ static expression_t *parse_cast(void)
        expect(')', end_error);
 
        if (token.type == '{') {
-               return parse_compound_literal(type);
+               return parse_compound_literal(&pos, type);
        }
 
        expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
-       cast->base.source_position = source_position;
+       cast->base.source_position = pos;
 
        expression_t *value = parse_subexpression(PREC_CAST);
        cast->base.type   = type;
@@ -6889,10 +6884,9 @@ static expression_t *parse_noop_expression(void)
 {
        /* the result is a (int)0 */
        expression_t *literal = allocate_expression_zero(EXPR_LITERAL_MS_NOOP);
-       literal->base.type            = type_int;
-       literal->base.source_position = token.source_position;
-       literal->literal.value.begin  = "__noop";
-       literal->literal.value.size   = 6;
+       literal->base.type           = type_int;
+       literal->literal.value.begin = "__noop";
+       literal->literal.value.size  = 6;
 
        eat(T___noop);
 
@@ -7053,6 +7047,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
        type_t       *orig_type;
        expression_t *expression;
        if (token.type == '(' && is_declaration_specifier(look_ahead(1))) {
+               source_position_t const pos = *HERE;
                next_token();
                add_anchor_token(')');
                orig_type = parse_typename();
@@ -7062,7 +7057,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
                if (token.type == '{') {
                        /* It was not sizeof(type) after all.  It is sizeof of an expression
                         * starting with a compound literal */
-                       expression = parse_compound_literal(orig_type);
+                       expression = parse_compound_literal(&pos, orig_type);
                        goto typeprop_expression;
                }
        } else {
@@ -7590,12 +7585,9 @@ types_incompatible:
  */
 static expression_t *parse_extension(void)
 {
-       eat(T___extension__);
-
-       bool old_gcc_extension   = in_gcc_extension;
-       in_gcc_extension         = true;
+       PUSH_EXTENSION();
        expression_t *expression = parse_subexpression(PREC_UNARY);
-       in_gcc_extension         = old_gcc_extension;
+       POP_EXTENSION();
        return expression;
 }
 
@@ -8759,7 +8751,6 @@ static expression_t *parse_subexpression(precedence_t precedence)
 
        expression_parser_function_t *parser
                = &expression_parsers[token.type];
-       source_position_t             source_position = token.source_position;
        expression_t                 *left;
 
        if (parser->parser != NULL) {
@@ -8768,7 +8759,6 @@ static expression_t *parse_subexpression(precedence_t precedence)
                left = parse_primary_expression();
        }
        assert(left != NULL);
-       left->base.source_position = source_position;
 
        while (true) {
                if (token.type < 0) {
@@ -8785,7 +8775,6 @@ static expression_t *parse_subexpression(precedence_t precedence)
 
                assert(left != NULL);
                assert(left->kind != EXPR_UNKNOWN);
-               left->base.source_position = source_position;
        }
 
        return left;
@@ -9103,7 +9092,8 @@ static statement_t *parse_label_inner_statement(statement_t const *const label,
 
                default:
                        inner_stmt = parse_statement();
-                       /* ISO/IEC 14882:1998(E) §6:1/§6.7  Declarations are statements */
+                       /* ISO/IEC  9899:1999(E) §6.8:1/6.8.2:1  Declarations are no statements */
+                       /* ISO/IEC 14882:1998(E) §6:1/§6.7       Declarations are statements */
                        if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
                                errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
                        }
@@ -9192,7 +9182,7 @@ end_error:
 
        statement->case_label.statement = parse_label_inner_statement(statement, "case label");
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 }
 
@@ -9232,7 +9222,7 @@ end_error:
 
        statement->case_label.statement = parse_label_inner_statement(statement, "default label");
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 }
 
@@ -9266,10 +9256,21 @@ static statement_t *parse_label_statement(void)
        *label_anchor = &statement->label;
        label_anchor  = &statement->label.next;
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 }
 
+static statement_t *parse_inner_statement(void)
+{
+       statement_t *const stmt = parse_statement();
+       /* ISO/IEC  9899:1999(E) §6.8:1/6.8.2:1  Declarations are no statements */
+       /* ISO/IEC 14882:1998(E) §6:1/§6.7       Declarations are statements */
+       if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+               errorf(&stmt->base.source_position, "declaration as inner statement, use {}");
+       }
+       return stmt;
+}
+
 /**
  * Parse an if statement.
  */
@@ -9298,19 +9299,19 @@ end_error:
        rem_anchor_token('{');
 
        add_anchor_token(T_else);
-       statement_t *const true_stmt = parse_statement();
+       statement_t *const true_stmt = parse_inner_statement();
        statement->ifs.true_statement = true_stmt;
        rem_anchor_token(T_else);
 
        if (next_if(T_else)) {
-               statement->ifs.false_statement = parse_statement();
+               statement->ifs.false_statement = parse_inner_statement();
        } else if (true_stmt->kind == STATEMENT_IF &&
                        true_stmt->ifs.false_statement != NULL) {
                source_position_t const *const pos = &true_stmt->base.source_position;
                warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
        }
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 }
 
@@ -9389,7 +9390,7 @@ static statement_t *parse_switch(void)
 
        switch_statement_t *rem = current_switch;
        current_switch          = &statement->switchs;
-       statement->switchs.body = parse_statement();
+       statement->switchs.body = parse_inner_statement();
        current_switch          = rem;
 
        if (statement->switchs.default_label == NULL) {
@@ -9397,10 +9398,10 @@ static statement_t *parse_switch(void)
        }
        check_enum_cases(&statement->switchs);
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 end_error:
-       POP_PARENT;
+       POP_PARENT();
        return create_invalid_statement();
 }
 
@@ -9409,7 +9410,7 @@ static statement_t *parse_loop_body(statement_t *const loop)
        statement_t *const rem = current_loop;
        current_loop = loop;
 
-       statement_t *const body = parse_statement();
+       statement_t *const body = parse_inner_statement();
 
        current_loop = rem;
        return body;
@@ -9439,10 +9440,10 @@ static statement_t *parse_while(void)
 
        statement->whiles.body = parse_loop_body(statement);
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 end_error:
-       POP_PARENT;
+       POP_PARENT();
        return create_invalid_statement();
 }
 
@@ -9474,10 +9475,10 @@ static statement_t *parse_do(void)
        expect(')', end_error);
        expect(';', end_error);
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 end_error:
-       POP_PARENT;
+       POP_PARENT();
        return create_invalid_statement();
 }
 
@@ -9494,14 +9495,9 @@ static statement_t *parse_for(void)
        add_anchor_token(')');
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE(&statement->fors.scope);
 
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&statement->fors.scope);
-
-       bool old_gcc_extension = in_gcc_extension;
-       while (next_if(T___extension__)) {
-               in_gcc_extension = true;
-       }
+       PUSH_EXTENSION();
 
        if (next_if(';')) {
        } else if (is_declaration_specifier(&token)) {
@@ -9517,7 +9513,8 @@ static statement_t *parse_for(void)
                rem_anchor_token(';');
                expect(';', end_error2);
        }
-       in_gcc_extension = old_gcc_extension;
+
+       POP_EXTENSION();
 
        if (token.type != ';') {
                add_anchor_token(';');
@@ -9542,19 +9539,14 @@ static statement_t *parse_for(void)
        rem_anchor_token(')');
        statement->fors.body = parse_loop_body(statement);
 
-       assert(current_scope == &statement->fors.scope);
-       scope_pop(old_scope);
-       environment_pop_to(top);
-
-       POP_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
 
 end_error2:
-       POP_PARENT;
+       POP_PARENT();
        rem_anchor_token(')');
-       assert(current_scope == &statement->fors.scope);
-       scope_pop(old_scope);
-       environment_pop_to(top);
+       POP_SCOPE();
        /* fallthrough */
 
 end_error1:
@@ -9721,9 +9713,8 @@ entity_t *expression_is_variable(const expression_t *expression)
  */
 static statement_t *parse_return(void)
 {
-       eat(T_return);
-
        statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
+       eat(T_return);
 
        expression_t *return_value = NULL;
        if (token.type != ';') {
@@ -9844,7 +9835,7 @@ static statement_t *parse_ms_try_statment(void)
        statement->ms_try.try_statement = parse_compound_statement(false);
        current_try = rem;
 
-       POP_PARENT;
+       POP_PARENT();
 
        if (next_if(T___except)) {
                expect('(', end_error);
@@ -9959,8 +9950,7 @@ static void parse_namespace_definition(void)
        environment_push(entity);
        append_entity(current_scope, entity);
 
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&entity->namespacee.members);
+       PUSH_SCOPE(&entity->namespacee.members);
 
        entity_t     *old_current_entity = current_entity;
        current_entity = entity;
@@ -9970,11 +9960,9 @@ static void parse_namespace_definition(void)
        expect('}', end_error);
 
 end_error:
-       assert(current_scope == &entity->namespacee.members);
        assert(current_entity == entity);
        current_entity = old_current_entity;
-       scope_pop(old_scope);
-       environment_pop_to(top);
+       POP_SCOPE();
 }
 
 /**
@@ -10017,15 +10005,14 @@ static statement_t *intern_parse_statement(void)
                break;
        }
 
-       case T___extension__:
+       case T___extension__: {
                /* This can be a prefix to a declaration or an expression statement.
                 * We simply eat it now and parse the rest with tail recursion. */
-               while (next_if(T___extension__)) {}
-               bool old_gcc_extension = in_gcc_extension;
-               in_gcc_extension       = true;
+               PUSH_EXTENSION();
                statement = intern_parse_statement();
-               in_gcc_extension = old_gcc_extension;
+               POP_EXTENSION();
                break;
+       }
 
        DECLARATION_START
                statement = parse_declaration_statement();
@@ -10099,6 +10086,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE(&statement->compound.scope);
 
        eat('{');
        add_anchor_token('}');
@@ -10191,9 +10179,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token(T_wchar_t);
        add_anchor_token(T_while);
 
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&statement->compound.scope);
-
        statement_t **anchor            = &statement->compound.statements;
        bool          only_decls_so_far = true;
        while (token.type != '}') {
@@ -10332,11 +10317,9 @@ end_error:
        rem_anchor_token('&');
        rem_anchor_token('!');
        rem_anchor_token('}');
-       assert(current_scope == &statement->compound.scope);
-       scope_pop(old_scope);
-       environment_pop_to(top);
 
-       POP_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
 }
 
@@ -10429,22 +10412,21 @@ end_error:
 static void parse_external(void)
 {
        switch (token.type) {
-               DECLARATION_START_NO_EXTERN
-               case T_IDENTIFIER:
-               case T___extension__:
-               /* tokens below are for implicit int */
-               case '&': /* & x; -> int& x; (and error later, because C++ has no
-                            implicit int) */
-               case '*': /* * x; -> int* x; */
-               case '(': /* (x); -> int (x); */
-                       parse_external_declaration();
-                       return;
-
                case T_extern:
                        if (look_ahead(1)->type == T_STRING_LITERAL) {
                                parse_linkage_specification();
                        } else {
+               DECLARATION_START_NO_EXTERN
+               case T_IDENTIFIER:
+               case T___extension__:
+               /* tokens below are for implicit int */
+               case '&':  /* & x; -> int& x; (and error later, because C++ has no
+                             implicit int) */
+               case '*':  /* * x; -> int* x; */
+               case '(':; /* (x); -> int (x); */
+                               PUSH_EXTENSION();
                                parse_external_declaration();
+                               POP_EXTENSION();
                        }
                        return;