Remove dead assignment and the stale assert, which checked for the dead value, with it.
[cparser] / parser.c
index 8986376..f1bbaa6 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -284,25 +284,26 @@ static void semantic_comparison(binary_expression_t *expression);
 static size_t get_statement_struct_size(statement_kind_t kind)
 {
        static const size_t sizes[] = {
-               [STATEMENT_ERROR]       = sizeof(statement_base_t),
-               [STATEMENT_EMPTY]       = sizeof(statement_base_t),
-               [STATEMENT_COMPOUND]    = sizeof(compound_statement_t),
-               [STATEMENT_RETURN]      = sizeof(return_statement_t),
-               [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
-               [STATEMENT_IF]          = sizeof(if_statement_t),
-               [STATEMENT_SWITCH]      = sizeof(switch_statement_t),
-               [STATEMENT_EXPRESSION]  = sizeof(expression_statement_t),
-               [STATEMENT_CONTINUE]    = sizeof(statement_base_t),
-               [STATEMENT_BREAK]       = sizeof(statement_base_t),
-               [STATEMENT_GOTO]        = sizeof(goto_statement_t),
-               [STATEMENT_LABEL]       = sizeof(label_statement_t),
-               [STATEMENT_CASE_LABEL]  = sizeof(case_label_statement_t),
-               [STATEMENT_WHILE]       = sizeof(while_statement_t),
-               [STATEMENT_DO_WHILE]    = sizeof(do_while_statement_t),
-               [STATEMENT_FOR]         = sizeof(for_statement_t),
-               [STATEMENT_ASM]         = sizeof(asm_statement_t),
-               [STATEMENT_MS_TRY]      = sizeof(ms_try_statement_t),
-               [STATEMENT_LEAVE]       = sizeof(leave_statement_t)
+               [STATEMENT_ERROR]         = sizeof(statement_base_t),
+               [STATEMENT_EMPTY]         = sizeof(statement_base_t),
+               [STATEMENT_COMPOUND]      = sizeof(compound_statement_t),
+               [STATEMENT_RETURN]        = sizeof(return_statement_t),
+               [STATEMENT_DECLARATION]   = sizeof(declaration_statement_t),
+               [STATEMENT_IF]            = sizeof(if_statement_t),
+               [STATEMENT_SWITCH]        = sizeof(switch_statement_t),
+               [STATEMENT_EXPRESSION]    = sizeof(expression_statement_t),
+               [STATEMENT_CONTINUE]      = sizeof(statement_base_t),
+               [STATEMENT_BREAK]         = sizeof(statement_base_t),
+               [STATEMENT_COMPUTED_GOTO] = sizeof(computed_goto_statement_t),
+               [STATEMENT_GOTO]          = sizeof(goto_statement_t),
+               [STATEMENT_LABEL]         = sizeof(label_statement_t),
+               [STATEMENT_CASE_LABEL]    = sizeof(case_label_statement_t),
+               [STATEMENT_WHILE]         = sizeof(while_statement_t),
+               [STATEMENT_DO_WHILE]      = sizeof(do_while_statement_t),
+               [STATEMENT_FOR]           = sizeof(for_statement_t),
+               [STATEMENT_ASM]           = sizeof(asm_statement_t),
+               [STATEMENT_MS_TRY]        = sizeof(ms_try_statement_t),
+               [STATEMENT_LEAVE]         = sizeof(leave_statement_t)
        };
        assert((size_t)kind < lengthof(sizes));
        assert(sizes[kind] != 0);
@@ -319,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),
@@ -998,10 +999,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;
                        }
@@ -1440,7 +1441,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;
 
@@ -1521,7 +1522,7 @@ unary:
                        determine_lhs_ent(expr->va_starte.ap, lhs_ent);
                        return;
 
-               EXPR_LITERAL_CASES
+               case EXPR_LITERAL_CASES:
                case EXPR_ERROR:
                case EXPR_STRING_LITERAL:
                case EXPR_WIDE_STRING_LITERAL:
@@ -1535,7 +1536,7 @@ unary:
                case EXPR_OFFSETOF:
                case EXPR_STATEMENT: // TODO
                case EXPR_LABEL_ADDRESS:
-               case EXPR_REFERENCE_ENUM_VALUE:
+               case EXPR_ENUM_CONSTANT:
                        return;
        }
 
@@ -1665,15 +1666,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
        return result;
 }
 
-/**
- * Checks if a given expression can be used as a constant initializer.
- */
-static bool is_initializer_constant(const expression_t *expression)
-{
-       return is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
-              is_linker_constant(expression)     != EXPR_CLASS_VARIABLE;
-}
-
 /**
  * Parses an scalar initializer.
  *
@@ -1694,7 +1686,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 
        expression_t *expression = parse_assignment_expression();
        mark_vars_read(expression, NULL);
-       if (must_be_constant && !is_initializer_constant(expression)) {
+       if (must_be_constant && !is_linker_constant(expression)) {
                errorf(&expression->base.source_position,
                       "initialisation expression '%E' is not constant",
                       expression);
@@ -2114,7 +2106,7 @@ finish_designator:
                        expression_t *expression = parse_assignment_expression();
                        mark_vars_read(expression, NULL);
 
-                       if (env->must_be_constant && !is_initializer_constant(expression)) {
+                       if (env->must_be_constant && !is_linker_constant(expression)) {
                                errorf(&expression->base.source_position,
                                       "Initialisation expression '%E' is not constant",
                                       expression);
@@ -3216,6 +3208,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);
@@ -3223,13 +3217,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;
 }
@@ -4629,10 +4630,6 @@ static void check_labels(void)
        for (const goto_statement_t *goto_statement = goto_first;
            goto_statement != NULL;
            goto_statement = goto_statement->next) {
-               /* skip computed gotos */
-               if (goto_statement->expression != NULL)
-                       continue;
-
                label_t *label = goto_statement->label;
                if (label->base.source_position.input_name == NULL) {
                        print_in_function();
@@ -4732,10 +4729,12 @@ static bool expression_returns(expression_t const *const expr)
        switch (expr->kind) {
                case EXPR_CALL: {
                        expression_t const *const func = expr->call.function;
-                       if (func->kind == EXPR_REFERENCE) {
-                               entity_t *entity = func->reference.entity;
-                               if (entity->kind == ENTITY_FUNCTION
-                                               && entity->declaration.modifiers & DM_NORETURN)
+                       type_t       const *const type = skip_typeref(func->base.type);
+                       if (type->kind == TYPE_POINTER) {
+                               type_t const *const points_to
+                                       = skip_typeref(type->pointer.points_to);
+                               if (points_to->kind == TYPE_FUNCTION
+                                   && points_to->function.modifiers & DM_NORETURN)
                                        return false;
                        }
 
@@ -4751,8 +4750,8 @@ static bool expression_returns(expression_t const *const expr)
                }
 
                case EXPR_REFERENCE:
-               case EXPR_REFERENCE_ENUM_VALUE:
-               EXPR_LITERAL_CASES
+               case EXPR_ENUM_CONSTANT:
+               case EXPR_LITERAL_CASES:
                case EXPR_STRING_LITERAL:
                case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
@@ -4805,13 +4804,13 @@ static bool expression_returns(expression_t const *const expr)
                case EXPR_VA_COPY:
                        return expression_returns(expr->va_copye.src);
 
-               EXPR_UNARY_CASES_MANDATORY
+               case EXPR_UNARY_CASES_MANDATORY:
                        return expression_returns(expr->unary.value);
 
                case EXPR_UNARY_THROW:
                        return false;
 
-               EXPR_BINARY_CASES
+               case EXPR_BINARY_CASES:
                        // TODO handle constant lhs of && and ||
                        return
                                expression_returns(expr->binary.left) &&
@@ -5010,20 +5009,21 @@ static void check_reachable(statement_t *const stmt)
 found_break_parent:
                        break;
 
-               case STATEMENT_GOTO:
-                       if (stmt->gotos.expression) {
-                               if (!expression_returns(stmt->gotos.expression))
-                                       return;
+               case STATEMENT_COMPUTED_GOTO: {
+                       if (!expression_returns(stmt->computed_goto.expression))
+                               return;
 
-                               statement_t *parent = stmt->base.parent;
-                               if (parent == NULL) /* top level goto */
-                                       return;
-                               next = parent;
-                       } else {
-                               next = stmt->gotos.label->statement;
-                               if (next == NULL) /* missing label */
-                                       return;
-                       }
+                       statement_t *parent = stmt->base.parent;
+                       if (parent == NULL) /* top level goto */
+                               return;
+                       next = parent;
+                       break;
+               }
+
+               case STATEMENT_GOTO:
+                       next = stmt->gotos.label->statement;
+                       if (next == NULL) /* missing label */
+                               return;
                        break;
 
                case STATEMENT_LABEL:
@@ -5120,8 +5120,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");
@@ -5138,6 +5138,7 @@ found_break_parent:
                        case STATEMENT_RETURN:
                        case STATEMENT_CONTINUE:
                        case STATEMENT_BREAK:
+                       case STATEMENT_COMPUTED_GOTO:
                        case STATEMENT_GOTO:
                        case STATEMENT_LEAVE:
                                panic("invalid control flow in function");
@@ -6241,7 +6242,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;
@@ -6281,7 +6282,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 */
@@ -6876,9 +6877,10 @@ static expression_t *parse_noop_expression(void)
                if (token.kind != ')') do {
                        (void)parse_assignment_expression();
                } while (next_if(','));
+
+               rem_anchor_token(',');
+               rem_anchor_token(')');
        }
-       rem_anchor_token(',');
-       rem_anchor_token(')');
        expect(')', end_error);
 
 end_error:
@@ -7059,7 +7061,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) {
@@ -7489,16 +7491,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;
@@ -7531,8 +7531,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))) {
@@ -7626,7 +7625,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");
        }
@@ -7657,8 +7656,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);
                                }
@@ -7681,7 +7679,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);
@@ -8195,7 +8193,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 {
@@ -8550,7 +8548,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 */
@@ -8618,7 +8616,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;
@@ -9586,10 +9584,12 @@ end_error1:
  */
 static statement_t *parse_goto(void)
 {
-       statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
-       eat(T_goto);
+       statement_t *statement;
+       if (GNU_MODE && look_ahead(1)->kind == '*') {
+               statement = allocate_statement_zero(STATEMENT_COMPUTED_GOTO);
+               eat(T_goto);
+               eat('*');
 
-       if (GNU_MODE && next_if('*')) {
                expression_t *expression = parse_expression();
                mark_vars_read(expression, NULL);
 
@@ -9607,24 +9607,28 @@ static statement_t *parse_goto(void)
                        expression = create_implicit_cast(expression, type_void_ptr);
                }
 
-               statement->gotos.expression = expression;
-       } else if (token.kind == T_IDENTIFIER) {
-               label_t *const label = get_label();
-               label->used            = true;
-               statement->gotos.label = label;
+               statement->computed_goto.expression = expression;
        } else {
-               if (GNU_MODE)
-                       parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
-               else
-                       parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
-               eat_until_anchor();
-               return create_error_statement();
+               statement = allocate_statement_zero(STATEMENT_GOTO);
+               eat(T_goto);
+               if (token.kind == T_IDENTIFIER) {
+                       label_t *const label = get_label();
+                       label->used            = true;
+                       statement->gotos.label = label;
+
+                       /* remember the goto's in a list for later checking */
+                       *goto_anchor = &statement->gotos;
+                       goto_anchor  = &statement->gotos.next;
+               } else {
+                       if (GNU_MODE)
+                               parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+                       else
+                               parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+                       eat_until_anchor();
+                       return create_error_statement();
+               }
        }
 
-       /* remember the goto's in a list for later checking */
-       *goto_anchor = &statement->gotos;
-       goto_anchor  = &statement->gotos.next;
-
        expect(';', end_error);
 
 end_error:
@@ -9736,6 +9740,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.
  */
@@ -9758,24 +9771,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);
@@ -9790,14 +9793,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;
 
@@ -10000,10 +9998,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;
@@ -10074,14 +10070,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;
 }
@@ -10126,6 +10117,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);
@@ -10338,6 +10330,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('*');