Do not truncate the existing attribute list if a __declspec has no arguments.
[cparser] / parser.c
index 73b0209..8d29162 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -320,7 +320,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
        static const size_t sizes[] = {
                [EXPR_ERROR]                      = sizeof(expression_base_t),
                [EXPR_REFERENCE]                  = sizeof(reference_expression_t),
-               [EXPR_REFERENCE_ENUM_VALUE]       = sizeof(reference_expression_t),
+               [EXPR_ENUM_CONSTANT]              = sizeof(reference_expression_t),
                [EXPR_LITERAL_BOOLEAN]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_INTEGER]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_INTEGER_OCTAL]      = sizeof(literal_expression_t),
@@ -546,17 +546,6 @@ static void rem_anchor_token(int token_kind)
        --token_anchor_set[token_kind];
 }
 
-/**
- * Return true if the token type of the current token is
- * in the anchor set.
- */
-static bool at_anchor(void)
-{
-       if (token.kind < 0)
-               return false;
-       return token_anchor_set[token.kind];
-}
-
 /**
  * Eat tokens until a matching token type is found.
  */
@@ -999,10 +988,10 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
                        points_to_left  = get_unqualified_type(points_to_left);
                        points_to_right = get_unqualified_type(points_to_right);
 
-                       if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID))
+                       if (is_type_void(points_to_left))
                                return res;
 
-                       if (is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) {
+                       if (is_type_void(points_to_right)) {
                                /* ISO/IEC 14882:1998(E) §C.1.2:6 */
                                return c_mode & _CXX ? ASSIGN_ERROR_INCOMPATIBLE : res;
                        }
@@ -1136,11 +1125,7 @@ static attribute_argument_t *parse_attribute_arguments(void)
                anchor  = &argument->next;
        } while (next_if(','));
        expect(')', end_error);
-
-       return first;
-
 end_error:
-       /* TODO... */
        return first;
 }
 
@@ -1441,7 +1426,7 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
 
                case EXPR_UNARY_CAST:
                        /* Special case: Use void cast to mark a variable as "read" */
-                       if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID))
+                       if (is_type_void(skip_typeref(expr->base.type)))
                                lhs_ent = NULL;
                        goto unary;
 
@@ -1536,7 +1521,7 @@ unary:
                case EXPR_OFFSETOF:
                case EXPR_STATEMENT: // TODO
                case EXPR_LABEL_ADDRESS:
-               case EXPR_REFERENCE_ENUM_VALUE:
+               case EXPR_ENUM_CONSTANT:
                        return;
        }
 
@@ -2674,32 +2659,27 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
        eat(T__declspec);
 
        expect('(', end_error);
+       if (token.kind != ')') {
+               add_anchor_token(')');
 
-       if (next_if(')'))
-               return NULL;
-
-       add_anchor_token(')');
-
-       attribute_t **anchor = &first;
-       do {
-               while (*anchor != NULL)
-                       anchor = &(*anchor)->next;
+               attribute_t **anchor = &first;
+               do {
+                       while (*anchor != NULL)
+                               anchor = &(*anchor)->next;
 
-               attribute_t *attribute
-                       = parse_microsoft_extended_decl_modifier_single();
-               if (attribute == NULL)
-                       goto end_error;
+                       attribute_t *attribute
+                               = parse_microsoft_extended_decl_modifier_single();
+                       if (attribute == NULL)
+                               break;
 
-               *anchor = attribute;
-               anchor  = &attribute->next;
-       } while (next_if(','));
+                       *anchor = attribute;
+                       anchor  = &attribute->next;
+               } while (next_if(','));
 
-       rem_anchor_token(')');
+               rem_anchor_token(')');
+       }
        expect(')', end_error);
-       return first;
-
 end_error:
-       rem_anchor_token(')');
        return first;
 }
 
@@ -3208,6 +3188,8 @@ static void semantic_parameter_incomplete(const entity_t *entity)
 static bool has_parameters(void)
 {
        /* func(void) is not a parameter */
+       if (look_ahead(1)->kind != ')')
+               return true;
        if (token.kind == T_IDENTIFIER) {
                entity_t const *const entity
                        = get_entity(token.identifier.symbol, NAMESPACE_NORMAL);
@@ -3215,13 +3197,20 @@ static bool has_parameters(void)
                        return true;
                if (entity->kind != ENTITY_TYPEDEF)
                        return true;
-               if (skip_typeref(entity->typedefe.type) != type_void)
+               type_t const *const type = skip_typeref(entity->typedefe.type);
+               if (!is_type_void(type))
                        return true;
+               if (c_mode & _CXX) {
+                       /* ISO/IEC 14882:1998(E) §8.3.5:2  It must be literally (void).  A typedef
+                        * is not allowed. */
+                       errorf(HERE, "empty parameter list defined with a typedef of 'void' not allowed in C++");
+               } else if (type->base.qualifiers != TYPE_QUALIFIER_NONE) {
+                       /* §6.7.5.3:10  Qualification is not allowed here. */
+                       errorf(HERE, "'void' as parameter must not have type qualifiers");
+               }
        } else if (token.kind != T_void) {
                return true;
        }
-       if (look_ahead(1)->kind != ')')
-               return true;
        next_token();
        return false;
 }
@@ -4741,7 +4730,7 @@ static bool expression_returns(expression_t const *const expr)
                }
 
                case EXPR_REFERENCE:
-               case EXPR_REFERENCE_ENUM_VALUE:
+               case EXPR_ENUM_CONSTANT:
                case EXPR_LITERAL_CASES:
                case EXPR_STRING_LITERAL:
                case EXPR_WIDE_STRING_LITERAL:
@@ -5111,8 +5100,8 @@ found_break_parent:
                        type_t *const type = skip_typeref(current_function->base.type);
                        assert(is_type_function(type));
                        type_t *const ret  = skip_typeref(type->function.return_type);
-                       if (!is_type_atomic(ret, ATOMIC_TYPE_VOID) &&
-                           is_type_valid(ret)                     &&
+                       if (!is_type_void(ret) &&
+                           is_type_valid(ret) &&
                            !is_sym_main(current_function->base.base.symbol)) {
                                source_position_t const *const pos = &stmt->base.source_position;
                                warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
@@ -6233,7 +6222,7 @@ static expression_t *parse_reference(void)
 
        expression_kind_t kind = EXPR_REFERENCE;
        if (entity->kind == ENTITY_ENUM_VALUE)
-               kind = EXPR_REFERENCE_ENUM_VALUE;
+               kind = EXPR_ENUM_CONSTANT;
 
        expression_t *expression         = allocate_expression_zero(kind);
        expression->base.source_position = pos;
@@ -6273,7 +6262,7 @@ static bool semantic_cast(expression_t *cast)
        source_position_t const *pos             = &cast->base.source_position;
 
        /* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
-       if (dst_type == type_void)
+       if (is_type_void(dst_type))
                return true;
 
        /* only integer and pointer can be casted to pointer */
@@ -7052,7 +7041,7 @@ typeprop_expression:
        type_t const* const type       = skip_typeref(orig_type);
        char   const*       wrong_type = NULL;
        if (is_type_incomplete(type)) {
-               if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE)
+               if (!is_type_void(type) || !GNU_MODE)
                        wrong_type = "incomplete";
        } else if (type->kind == TYPE_FUNCTION) {
                if (GNU_MODE) {
@@ -7482,16 +7471,14 @@ end_error:;
        /* 6.5.15.3 */
        source_position_t const *const pos = &conditional->base.source_position;
        type_t                        *result_type;
-       if (is_type_atomic(true_type,  ATOMIC_TYPE_VOID) ||
-                       is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+       if (is_type_void(true_type) || is_type_void(false_type)) {
                /* ISO/IEC 14882:1998(E) §5.16:2 */
                if (true_expression->kind == EXPR_UNARY_THROW) {
                        result_type = false_type;
                } else if (false_expression->kind == EXPR_UNARY_THROW) {
                        result_type = true_type;
                } else {
-                       if (!is_type_atomic(true_type,  ATOMIC_TYPE_VOID) ||
-                           !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+                       if (!is_type_void(true_type) || !is_type_void(false_type)) {
                                warningf(WARN_OTHER, pos, "ISO C forbids conditional expression with only one void side");
                        }
                        result_type = type_void;
@@ -7524,8 +7511,7 @@ end_error:;
                        type_t *to2 = skip_typeref(other_type->pointer.points_to);
 
                        type_t *to;
-                       if (is_type_atomic(to1, ATOMIC_TYPE_VOID) ||
-                           is_type_atomic(to2, ATOMIC_TYPE_VOID)) {
+                       if (is_type_void(to1) || is_type_void(to2)) {
                                to = type_void;
                        } else if (types_compatible(get_unqualified_type(to1),
                                                    get_unqualified_type(to2))) {
@@ -7619,7 +7605,7 @@ end_error:;
                        errorf(&value->base.source_position,
                                        "operand of delete must have pointer type");
                }
-       } else if (is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) {
+       } else if (is_type_void(skip_typeref(type->pointer.points_to))) {
                source_position_t const *const pos = &value->base.source_position;
                warningf(WARN_OTHER, pos, "deleting 'void*' is undefined");
        }
@@ -7650,8 +7636,7 @@ static expression_t *parse_throw(void)
                                                "cannot throw object of incomplete type '%T'", orig_type);
                        } else if (is_type_pointer(type)) {
                                type_t *const points_to = skip_typeref(type->pointer.points_to);
-                               if (is_type_incomplete(points_to) &&
-                                               !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+                               if (is_type_incomplete(points_to) && !is_type_void(points_to)) {
                                        errorf(&value->base.source_position,
                                                        "cannot throw pointer to incomplete type '%T'", orig_type);
                                }
@@ -7674,7 +7659,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position,
        points_to = skip_typeref(points_to);
 
        if (is_type_incomplete(points_to)) {
-               if (!GNU_MODE || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+               if (!GNU_MODE || !is_type_void(points_to)) {
                        errorf(source_position,
                               "arithmetic with pointer to incomplete type '%T' not allowed",
                               orig_pointer_type);
@@ -8188,7 +8173,7 @@ static void semantic_sub(binary_expression_t *expression)
                               "subtracting pointers to incompatible types '%T' and '%T'",
                               orig_type_left, orig_type_right);
                } else if (!is_type_object(unqual_left)) {
-                       if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) {
+                       if (!is_type_void(unqual_left)) {
                                errorf(pos, "subtracting pointers to non-object types '%T'",
                                       orig_type_left);
                        } else {
@@ -8543,7 +8528,7 @@ static bool expression_has_effect(const expression_t *const expr)
        switch (expr->kind) {
                case EXPR_ERROR:                      return true; /* do NOT warn */
                case EXPR_REFERENCE:                  return false;
-               case EXPR_REFERENCE_ENUM_VALUE:       return false;
+               case EXPR_ENUM_CONSTANT:              return false;
                case EXPR_LABEL_ADDRESS:              return false;
 
                /* suppress the warning for microsoft __noop operations */
@@ -8611,7 +8596,7 @@ static bool expression_has_effect(const expression_t *const expr)
                 * suppress the warning */
                case EXPR_UNARY_CAST: {
                        type_t *const type = skip_typeref(expr->base.type);
-                       return is_type_atomic(type, ATOMIC_TYPE_VOID);
+                       return is_type_void(type);
                }
 
                case EXPR_UNARY_ASSUME:               return true;
@@ -9043,6 +9028,7 @@ end_of_asm:
        expect(')', end_error);
        expect(';', end_error);
 
+end_error:
        if (asm_statement->outputs == NULL) {
                /* GCC: An 'asm' instruction without any output operands will be treated
                 * identically to a volatile 'asm' instruction. */
@@ -9050,8 +9036,6 @@ end_of_asm:
        }
 
        return statement;
-end_error:
-       return create_error_statement();
 }
 
 static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
@@ -9282,6 +9266,23 @@ static statement_t *parse_inner_statement(void)
        return stmt;
 }
 
+/**
+ * Parse an expression in parentheses and mark its variables as read.
+ */
+static expression_t *parse_condition(void)
+{
+       expect('(', end_error0);
+       add_anchor_token(')');
+       expression_t *const expr = parse_expression();
+       mark_vars_read(expr, NULL);
+       rem_anchor_token(')');
+       expect(')', end_error1);
+end_error1:
+       return expr;
+end_error0:
+       return create_error_expression();
+}
+
 /**
  * Parse an if statement.
  */
@@ -9295,18 +9296,12 @@ static statement_t *parse_if(void)
 
        add_anchor_token('{');
 
-       expect('(', end_error);
-       add_anchor_token(')');
-       expression_t *const expr = parse_expression();
+       expression_t *const expr = parse_condition();
        statement->ifs.condition = expr;
        /* §6.8.4.1:1  The controlling expression of an if statement shall have
         *             scalar type. */
        semantic_condition(expr, "condition of 'if'-statment");
-       mark_vars_read(expr, NULL);
-       rem_anchor_token(')');
-       expect(')', end_error);
 
-end_error:
        rem_anchor_token('{');
 
        add_anchor_token(T_else);
@@ -9390,10 +9385,7 @@ static statement_t *parse_switch(void)
 
        PUSH_PARENT(statement);
 
-       expect('(', end_error);
-       add_anchor_token(')');
-       expression_t *const expr = parse_expression();
-       mark_vars_read(expr, NULL);
+       expression_t *const expr = parse_condition();
        type_t       *      type = skip_typeref(expr->base.type);
        if (is_type_integer(type)) {
                type = promote_integer(type);
@@ -9406,8 +9398,6 @@ static statement_t *parse_switch(void)
                type = type_error_type;
        }
        statement->switchs.expression = create_implicit_cast(expr, type);
-       expect(')', end_error);
-       rem_anchor_token(')');
 
        switch_statement_t *rem = current_switch;
        current_switch          = &statement->switchs;
@@ -9421,9 +9411,6 @@ static statement_t *parse_switch(void)
 
        POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT();
-       return create_error_statement();
 }
 
 static statement_t *parse_loop_body(statement_t *const loop)
@@ -9448,24 +9435,16 @@ static statement_t *parse_while(void)
 
        PUSH_PARENT(statement);
 
-       expect('(', end_error);
-       add_anchor_token(')');
-       expression_t *const cond = parse_expression();
+       expression_t *const cond = parse_condition();
        statement->whiles.condition = cond;
        /* §6.8.5:2    The controlling expression of an iteration statement shall
         *             have scalar type. */
        semantic_condition(cond, "condition of 'while'-statement");
-       mark_vars_read(cond, NULL);
-       rem_anchor_token(')');
-       expect(')', end_error);
 
        statement->whiles.body = parse_loop_body(statement);
 
        POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT();
-       return create_error_statement();
 }
 
 /**
@@ -9483,24 +9462,18 @@ static statement_t *parse_do(void)
        statement->do_while.body = parse_loop_body(statement);
        rem_anchor_token(T_while);
 
-       expect(T_while, end_error);
-       expect('(', end_error);
-       add_anchor_token(')');
-       expression_t *const cond = parse_expression();
+       expect(T_while, end_error0);
+end_error0:;
+       expression_t *const cond = parse_condition();
        statement->do_while.condition = cond;
        /* §6.8.5:2    The controlling expression of an iteration statement shall
         *             have scalar type. */
        semantic_condition(cond, "condition of 'do-while'-statement");
-       mark_vars_read(cond, NULL);
-       rem_anchor_token(')');
-       expect(')', end_error);
-       expect(';', end_error);
+       expect(';', end_error1);
+end_error1:
 
        POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT();
-       return create_error_statement();
 }
 
 /**
@@ -9512,12 +9485,12 @@ static statement_t *parse_for(void)
 
        eat(T_for);
 
-       expect('(', end_error1);
-       add_anchor_token(')');
-
        PUSH_PARENT(statement);
        PUSH_SCOPE(&statement->fors.scope);
 
+       expect('(', end_error1);
+       add_anchor_token(')');
+
        PUSH_EXTENSION();
 
        if (next_if(';')) {
@@ -9532,7 +9505,8 @@ static statement_t *parse_for(void)
                        warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
                }
                rem_anchor_token(';');
-               expect(';', end_error2);
+               expect(';', end_error3);
+end_error3:;
        }
 
        POP_EXTENSION();
@@ -9548,6 +9522,7 @@ static statement_t *parse_for(void)
                rem_anchor_token(';');
        }
        expect(';', end_error2);
+end_error2:
        if (token.kind != ')') {
                expression_t *const step = parse_expression();
                statement->fors.step = step;
@@ -9556,22 +9531,14 @@ static statement_t *parse_for(void)
                        warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect");
                }
        }
-       expect(')', end_error2);
        rem_anchor_token(')');
+       expect(')', end_error1);
+end_error1:
        statement->fors.body = parse_loop_body(statement);
 
        POP_SCOPE();
        POP_PARENT();
        return statement;
-
-end_error2:
-       POP_PARENT();
-       rem_anchor_token(')');
-       POP_SCOPE();
-       /* fallthrough */
-
-end_error1:
-       return create_error_statement();
 }
 
 /**
@@ -9620,7 +9587,7 @@ static statement_t *parse_goto(void)
                        else
                                parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
                        eat_until_anchor();
-                       return create_error_statement();
+                       statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous)->label;
                }
        }
 
@@ -9735,6 +9702,15 @@ entity_t *expression_is_variable(const expression_t *expression)
        return entity;
 }
 
+static void err_or_warn(source_position_t const *const pos, char const *const msg)
+{
+       if (c_mode & _CXX || strict_mode) {
+               errorf(pos, msg);
+       } else {
+               warningf(WARN_OTHER, pos, msg);
+       }
+}
+
 /**
  * Parse a return statement.
  */
@@ -9757,24 +9733,14 @@ static statement_t *parse_return(void)
        if (return_value != NULL) {
                type_t *return_value_type = skip_typeref(return_value->base.type);
 
-               if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
-                       if (is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
+               if (is_type_void(return_type)) {
+                       if (!is_type_void(return_value_type)) {
                                /* ISO/IEC 14882:1998(E) §6.6.3:2 */
                                /* Only warn in C mode, because GCC does the same */
-                               if (c_mode & _CXX || strict_mode) {
-                                       errorf(pos,
-                                                       "'return' with a value, in function returning 'void'");
-                               } else {
-                                       warningf(WARN_OTHER, pos, "'return' with a value, in function returning 'void'");
-                               }
+                               err_or_warn(pos, "'return' with a value, in function returning 'void'");
                        } else if (!(c_mode & _CXX)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */
                                /* Only warn in C mode, because GCC does the same */
-                               if (strict_mode) {
-                                       errorf(pos,
-                                                       "'return' with expression in function returning 'void'");
-                               } else {
-                                       warningf(WARN_OTHER, pos, "'return' with expression in function returning 'void'");
-                               }
+                               err_or_warn(pos, "'return' with expression in function returning 'void'");
                        }
                } else {
                        assign_error_t error = semantic_assign(return_type, return_value);
@@ -9789,14 +9755,9 @@ static statement_t *parse_return(void)
                                warningf(WARN_OTHER, pos, "function returns address of local variable");
                        }
                }
-       } else if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
+       } else if (!is_type_void(return_type)) {
                /* ISO/IEC 14882:1998(E) §6.6.3:3 */
-               if (c_mode & _CXX || strict_mode) {
-                       errorf(pos,
-                              "'return' without value, in function returning non-void");
-               } else {
-                       warningf(WARN_OTHER, pos, "'return' without value, in function returning non-void");
-               }
+               err_or_warn(pos, "'return' without value, in function returning non-void");
        }
        statement->returns.value = return_value;
 
@@ -9865,10 +9826,7 @@ static statement_t *parse_ms_try_statment(void)
        POP_PARENT();
 
        if (next_if(T___except)) {
-               expect('(', end_error);
-               add_anchor_token(')');
-               expression_t *const expr = parse_expression();
-               mark_vars_read(expr, NULL);
+               expression_t *const expr = parse_condition();
                type_t       *      type = skip_typeref(expr->base.type);
                if (is_type_integer(type)) {
                        type = promote_integer(type);
@@ -9878,18 +9836,11 @@ static statement_t *parse_ms_try_statment(void)
                        type = type_error_type;
                }
                statement->ms_try.except_expression = create_implicit_cast(expr, type);
-               rem_anchor_token(')');
-               expect(')', end_error);
-               statement->ms_try.final_statement = parse_compound_statement(false);
-       } else if (next_if(T__finally)) {
-               statement->ms_try.final_statement = parse_compound_statement(false);
-       } else {
+       } else if (!next_if(T__finally)) {
                parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
-               return create_error_statement();
        }
+       statement->ms_try.final_statement = parse_compound_statement(false);
        return statement;
-end_error:
-       return create_error_statement();
 }
 
 static statement_t *parse_empty_statement(void)
@@ -9999,10 +9950,8 @@ end_error:
  */
 static statement_t *intern_parse_statement(void)
 {
-       statement_t *statement = NULL;
-
        /* declaration or statement */
-       add_anchor_token(';');
+       statement_t *statement;
        switch (token.kind) {
        case T_IDENTIFIER: {
                token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
@@ -10073,14 +10022,9 @@ static statement_t *intern_parse_statement(void)
        default:
                errorf(HERE, "unexpected token %K while parsing statement", &token);
                statement = create_error_statement();
-               if (!at_anchor())
-                       next_token();
+               eat_until_anchor();
                break;
        }
-       rem_anchor_token(';');
-
-       assert(statement != NULL
-                       && statement->base.source_position.input_name != NULL);
 
        return statement;
 }
@@ -10125,6 +10069,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token('*');
        add_anchor_token('+');
        add_anchor_token('-');
+       add_anchor_token(';');
        add_anchor_token('{');
        add_anchor_token('~');
        add_anchor_token(T_CHARACTER_CONSTANT);
@@ -10208,18 +10153,10 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
 
        statement_t **anchor            = &statement->compound.statements;
        bool          only_decls_so_far = true;
-       while (token.kind != '}') {
-               if (token.kind == T_EOF) {
-                       errorf(&statement->base.source_position,
-                              "EOF while parsing compound statement");
-                       break;
-               }
+       while (token.kind != '}' && token.kind != T_EOF) {
                statement_t *sub_statement = intern_parse_statement();
                if (sub_statement->kind == STATEMENT_ERROR) {
-                       /* an error occurred. if we are at an anchor, return */
-                       if (at_anchor())
-                               goto end_error;
-                       continue;
+                       break;
                }
 
                if (sub_statement->kind != STATEMENT_DECLARATION) {
@@ -10230,13 +10167,10 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
                }
 
                *anchor = sub_statement;
-
-               while (sub_statement->base.next != NULL)
-                       sub_statement = sub_statement->base.next;
-
-               anchor = &sub_statement->base.next;
+               anchor  = &sub_statement->base.next;
        }
-       next_token();
+       expect('}', end_error);
+end_error:
 
        /* look over all statements again to produce no effect warnings */
        if (is_warn_on(WARN_UNUSED_VALUE)) {
@@ -10256,7 +10190,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
                }
        }
 
-end_error:
        rem_anchor_token(T_while);
        rem_anchor_token(T_wchar_t);
        rem_anchor_token(T_volatile);
@@ -10337,6 +10270,7 @@ end_error:
        rem_anchor_token(T_CHARACTER_CONSTANT);
        rem_anchor_token('~');
        rem_anchor_token('{');
+       rem_anchor_token(';');
        rem_anchor_token('-');
        rem_anchor_token('+');
        rem_anchor_token('*');