Update libfirm, which corrects the handling of externally visible, but locally define...
[cparser] / parser.c
index 463a444..7d8afab 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -23,6 +23,7 @@
 #include <stdarg.h>
 #include <stdbool.h>
 
+#include "adt/strutil.h"
 #include "parser.h"
 #include "diagnostic.h"
 #include "format_check.h"
@@ -117,8 +118,9 @@ static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 #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))
+       scope_t *const old_scope = (new_scope ? scope_push(new_scope) : NULL)
+#define PUSH_SCOPE_STATEMENT(scope) PUSH_SCOPE(c_mode & (_C99 | _CXX) ? (scope) : NULL)
+#define POP_SCOPE() (new_scope ? assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top) : (void)0)
 
 #define PUSH_EXTENSION() \
        (void)0; \
@@ -283,25 +285,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);
@@ -318,7 +321,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),
@@ -544,17 +547,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.
  */
@@ -662,21 +654,37 @@ static void type_error_incompatible(const char *msg,
 
 /**
  * Expect the current token is the expected token.
- * If not, generate an error, eat the current statement,
- * and goto the error_label label.
- */
-#define expect(expected, error_label)                     \
-       do {                                                  \
-               if (UNLIKELY(token.kind != (expected))) {         \
-                       parse_error_expected(NULL, (expected), NULL); \
-                       add_anchor_token(expected);                   \
-                       eat_until_anchor();                           \
-                       rem_anchor_token(expected);                   \
-                       if (token.kind != (expected))                 \
-                         goto error_label;                           \
-               }                                                 \
-               next_token();                                     \
-       } while (0)
+ * If not, generate an error and skip until the next anchor.
+ */
+static void expect(token_kind_t const expected)
+{
+       if (UNLIKELY(token.kind != expected)) {
+               parse_error_expected(NULL, expected, NULL);
+               add_anchor_token(expected);
+               eat_until_anchor();
+               rem_anchor_token(expected);
+               if (token.kind != expected)
+                       return;
+       }
+       eat(expected);
+}
+
+static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
+{
+       if (token.kind != T_IDENTIFIER) {
+               parse_error_expected(context, T_IDENTIFIER, NULL);
+               add_anchor_token(T_IDENTIFIER);
+               eat_until_anchor();
+               rem_anchor_token(T_IDENTIFIER);
+               if (token.kind != T_IDENTIFIER)
+                       return NULL;
+       }
+       symbol_t *const sym = token.identifier.symbol;
+       if (pos)
+               *pos = *HERE;
+       eat(T_IDENTIFIER);
+       return sym;
+}
 
 /**
  * Push a given scope on the scope stack and make it the
@@ -997,10 +1005,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;
                        }
@@ -1071,22 +1079,6 @@ static string_t parse_string_literals(void)
        return result;
 }
 
-/**
- * compare two string, ignoring double underscores on the second.
- */
-static int strcmp_underscore(const char *s1, const char *s2)
-{
-       if (s2[0] == '_' && s2[1] == '_') {
-               size_t len2 = strlen(s2);
-               size_t len1 = strlen(s1);
-               if (len1 == len2-4 && s2[len2-2] == '_' && s2[len2-1] == '_') {
-                       return strncmp(s1, s2+2, len2-4);
-               }
-       }
-
-       return strcmp(s1, s2);
-}
-
 static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
 {
        attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
@@ -1149,12 +1141,7 @@ static attribute_argument_t *parse_attribute_arguments(void)
                *anchor = argument;
                anchor  = &argument->next;
        } while (next_if(','));
-       expect(')', end_error);
-
-       return first;
-
-end_error:
-       /* TODO... */
+       expect(')');
        return first;
 }
 
@@ -1162,13 +1149,9 @@ static attribute_t *parse_attribute_asm(void)
 {
        attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
        eat(T_asm);
-
-       expect('(', end_error);
+       expect('(');
        attribute->a.arguments = parse_attribute_arguments();
        return attribute;
-
-end_error:
-       return NULL;
 }
 
 static symbol_t *get_symbol_from_token(void)
@@ -1231,8 +1214,7 @@ static attribute_t *parse_attribute_gnu_single(void)
                }
 
                const char *attribute_name = get_attribute_name(kind);
-               if (attribute_name != NULL
-                               && strcmp_underscore(attribute_name, name) == 0)
+               if (attribute_name != NULL && streq_underscore(attribute_name, name))
                        break;
        }
 
@@ -1252,21 +1234,23 @@ static attribute_t *parse_attribute_gnu(void)
        attribute_t **anchor = &first;
 
        eat(T___attribute__);
-       expect('(', end_error);
-       expect('(', end_error);
+       expect('(');
+       expect('(');
 
+       add_anchor_token(')');
+       add_anchor_token(',');
        if (token.kind != ')') do {
                attribute_t *attribute = parse_attribute_gnu_single();
-               if (attribute == NULL)
-                       goto end_error;
-
-               *anchor = attribute;
-               anchor  = &attribute->next;
+               if (attribute) {
+                       *anchor = attribute;
+                       anchor  = &attribute->next;
+               }
        } while (next_if(','));
-       expect(')', end_error);
-       expect(')', end_error);
+       rem_anchor_token(',');
+       rem_anchor_token(')');
 
-end_error:
+       expect(')');
+       expect(')');
        return first;
 }
 
@@ -1456,7 +1440,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;
 
@@ -1537,7 +1521,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:
@@ -1551,7 +1535,7 @@ unary:
                case EXPR_OFFSETOF:
                case EXPR_STATEMENT: // TODO
                case EXPR_LABEL_ADDRESS:
-               case EXPR_REFERENCE_ENUM_VALUE:
+               case EXPR_ENUM_CONSTANT:
                        return;
        }
 
@@ -1573,22 +1557,18 @@ static designator_t *parse_designation(void)
                        add_anchor_token(']');
                        designator->array_index = parse_constant_expression();
                        rem_anchor_token(']');
-                       expect(']', end_error);
+                       expect(']');
                        break;
                case '.':
                        designator = allocate_ast_zero(sizeof(designator[0]));
                        designator->source_position = token.base.source_position;
                        next_token();
-                       if (token.kind != T_IDENTIFIER) {
-                               parse_error_expected("while parsing designator",
-                                                    T_IDENTIFIER, NULL);
+                       designator->symbol = expect_identifier("while parsing designator", NULL);
+                       if (!designator->symbol)
                                return NULL;
-                       }
-                       designator->symbol = token.identifier.symbol;
-                       next_token();
                        break;
                default:
-                       expect('=', end_error);
+                       expect('=');
                        return result;
                }
 
@@ -1596,8 +1576,6 @@ static designator_t *parse_designation(void)
                *anchor = designator;
                anchor  = &designator->next;
        }
-end_error:
-       return NULL;
 }
 
 static initializer_t *initializer_from_string(array_type_t *const type,
@@ -1681,15 +1659,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.
  *
@@ -1710,7 +1679,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);
@@ -2117,20 +2086,19 @@ finish_designator:
                                                            env);
                                rem_anchor_token('}');
 
-                               if (type != NULL) {
-                                       ascend_from_subtype(path);
-                                       expect('}', end_error);
-                               } else {
-                                       expect('}', end_error);
+                               expect('}');
+
+                               if (!type)
                                        goto error_parse_next;
-                               }
+
+                               ascend_from_subtype(path);
                        }
                } else {
                        /* must be an expression */
                        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);
@@ -2210,7 +2178,9 @@ error_parse_next:
                if (token.kind == '}') {
                        break;
                }
-               expect(',', end_error);
+               add_anchor_token('}');
+               expect(',');
+               rem_anchor_token('}');
                if (token.kind == '}') {
                        break;
                }
@@ -2287,8 +2257,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                max_index = path.max_index;
                DEL_ARR_F(path.path);
 
-               expect('}', end_error);
-end_error:;
+               expect('}');
        } else {
                /* parse_scalar_initializer() also works in this case: we simply
                 * have an expression without {} around it */
@@ -2391,10 +2360,9 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol);
-               entity->compound.alignment   = 1;
-               entity->base.source_position = pos;
-               entity->base.parent_scope    = current_scope;
+               entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol, &pos);
+               entity->compound.alignment = 1;
+               entity->base.parent_scope  = current_scope;
                if (symbol != NULL) {
                        environment_push(entity);
                }
@@ -2429,20 +2397,14 @@ static void parse_enum_entries(type_t *const enum_type)
        }
 
        add_anchor_token('}');
+       add_anchor_token(',');
        do {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing enum entry", T_IDENTIFIER, NULL);
-                       eat_block();
-                       rem_anchor_token('}');
-                       return;
-               }
-
-               symbol_t *symbol       = token.identifier.symbol;
-               entity_t *const entity
-                       = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol);
+               add_anchor_token('=');
+               source_position_t pos;
+               symbol_t *const symbol = expect_identifier("while parsing enum entry", &pos);
+               entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol, &pos);
                entity->enum_value.enum_type = enum_type;
-               entity->base.source_position = token.base.source_position;
-               next_token();
+               rem_anchor_token('=');
 
                if (next_if('=')) {
                        expression_t *value = parse_constant_expression();
@@ -2455,12 +2417,10 @@ static void parse_enum_entries(type_t *const enum_type)
 
                record_entity(entity, false);
        } while (next_if(',') && token.kind != '}');
+       rem_anchor_token(',');
        rem_anchor_token('}');
 
-       expect('}', end_error);
-
-end_error:
-       ;
+       expect('}');
 }
 
 static type_t *parse_enum_specifier(void)
@@ -2501,9 +2461,8 @@ static type_t *parse_enum_specifier(void)
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol);
-               entity->base.source_position = pos;
-               entity->base.parent_scope    = current_scope;
+               entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol, &pos);
+               entity->base.parent_scope = current_scope;
        }
 
        type_t *const type     = allocate_type_zero(TYPE_ENUM);
@@ -2547,7 +2506,7 @@ static type_t *parse_typeof(void)
 
        type_t *type;
 
-       expect('(', end_error);
+       expect('(');
        add_anchor_token(')');
 
        expression_t *expression  = NULL;
@@ -2566,15 +2525,13 @@ static type_t *parse_typeof(void)
        }
 
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        type_t *typeof_type              = allocate_type_zero(TYPE_TYPEOF);
        typeof_type->typeoft.expression  = expression;
        typeof_type->typeoft.typeof_type = type;
 
        return typeof_type;
-end_error:
-       return NULL;
 }
 
 typedef enum specifiers_t {
@@ -2613,45 +2570,43 @@ static type_t *get_typedef_type(symbol_t *symbol)
 
 static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
 {
-       expect('(', end_error);
+       attribute_property_argument_t *const property = allocate_ast_zero(sizeof(*property));
 
-       attribute_property_argument_t *property
-               = allocate_ast_zero(sizeof(*property));
+       expect('(');
 
+       add_anchor_token(')');
+       add_anchor_token(',');
        do {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing property declspec",
-                                            T_IDENTIFIER, NULL);
-                       goto end_error;
-               }
+               add_anchor_token('=');
+               source_position_t pos;
+               symbol_t *const prop_sym = expect_identifier("while parsing property declspec", &pos);
+               rem_anchor_token('=');
 
-               symbol_t **prop;
-               symbol_t  *symbol = token.identifier.symbol;
-               if (strcmp(symbol->string, "put") == 0) {
-                       prop = &property->put_symbol;
-               } else if (strcmp(symbol->string, "get") == 0) {
-                       prop = &property->get_symbol;
-               } else {
-                       errorf(HERE, "expected put or get in property declspec");
-                       prop = NULL;
-               }
-               eat(T_IDENTIFIER);
-               expect('=', end_error);
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing property declspec",
-                                            T_IDENTIFIER, NULL);
-                       goto end_error;
+               symbol_t **prop = NULL;
+               if (prop_sym) {
+                       if (streq(prop_sym->string, "put")) {
+                               prop = &property->put_symbol;
+                       } else if (streq(prop_sym->string, "get")) {
+                               prop = &property->get_symbol;
+                       } else {
+                               errorf(&pos, "expected put or get in property declspec, but got '%Y'", prop_sym);
+                       }
                }
+
+               add_anchor_token(T_IDENTIFIER);
+               expect('=');
+               rem_anchor_token(T_IDENTIFIER);
+
+               symbol_t *const sym = expect_identifier("while parsing property declspec", NULL);
                if (prop != NULL)
-                       *prop = token.identifier.symbol;
-               next_token();
+                       *prop = sym ? sym : sym_anonymous;
        } while (next_if(','));
+       rem_anchor_token(',');
+       rem_anchor_token(')');
 
        attribute->a.property = property;
 
-       expect(')', end_error);
-
-end_error:
+       expect(')');
        return attribute;
 }
 
@@ -2665,7 +2620,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
                for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
                     ++k) {
                        const char *attribute_name = get_attribute_name(k);
-                       if (attribute_name != NULL && strcmp(attribute_name, name) == 0) {
+                       if (attribute_name != NULL && streq(attribute_name, name)) {
                                kind = k;
                                break;
                        }
@@ -2697,40 +2652,33 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 {
        eat(T__declspec);
 
-       expect('(', end_error);
-
-       if (next_if(')'))
-               return NULL;
-
-       add_anchor_token(')');
-
-       attribute_t **anchor = &first;
-       do {
-               while (*anchor != NULL)
-                       anchor = &(*anchor)->next;
+       expect('(');
+       if (token.kind != ')') {
+               add_anchor_token(')');
 
-               attribute_t *attribute
-                       = parse_microsoft_extended_decl_modifier_single();
-               if (attribute == NULL)
-                       goto end_error;
+               attribute_t **anchor = &first;
+               do {
+                       while (*anchor != NULL)
+                               anchor = &(*anchor)->next;
 
-               *anchor = attribute;
-               anchor  = &attribute->next;
-       } while (next_if(','));
+                       attribute_t *attribute
+                               = parse_microsoft_extended_decl_modifier_single();
+                       if (attribute == NULL)
+                               break;
 
-       rem_anchor_token(')');
-       expect(')', end_error);
-       return first;
+                       *anchor = attribute;
+                       anchor  = &attribute->next;
+               } while (next_if(','));
 
-end_error:
-       rem_anchor_token(')');
+               rem_anchor_token(')');
+       }
+       expect(')');
        return first;
 }
 
 static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
 {
-       entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol);
-       entity->base.source_position = *HERE;
+       entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol, HERE);
        if (is_declaration(entity)) {
                entity->declaration.type     = type_error_type;
                entity->declaration.implicit = true;
@@ -3194,8 +3142,7 @@ static void parse_identifier_list(scope_t *scope)
 {
        assert(token.kind == T_IDENTIFIER);
        do {
-               entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol);
-               entity->base.source_position = token.base.source_position;
+               entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol, HERE);
                /* a K&R parameter has no type, yet */
                next_token();
 
@@ -3232,6 +3179,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);
@@ -3239,13 +3188,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;
 }
@@ -3316,9 +3272,8 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
 
 parameters_finished:
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
-end_error:
        restore_anchor_state(',', saved_comma_state);
 }
 
@@ -3444,9 +3399,7 @@ static construct_type_t *parse_array_declarator(void)
                errorf(&array->base.pos, "static array parameters require a size");
 
        rem_anchor_token(']');
-       expect(']', end_error);
-
-end_error:
+       expect(']');
        return cons;
 }
 
@@ -3560,7 +3513,7 @@ ptr_operator_end: ;
                                                env->must_be_abstract = true;
                                        }
                                        rem_anchor_token(')');
-                                       expect(')', end_error);
+                                       expect(')');
                                }
                                break;
                }
@@ -3609,8 +3562,6 @@ declarator_finished:
        *anchor = inner_types;
 
        return first;
-end_error:
-       return NULL;
 }
 
 static type_t *construct_declarator_type(construct_type_t *construct_list,
@@ -3784,9 +3735,8 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        entity_t *entity;
        if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
-               entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol);
-               entity->base.source_position = env.source_position;
-               entity->typedefe.type        = orig_type;
+               entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.source_position);
+               entity->typedefe.type = orig_type;
 
                if (anonymous_entity != NULL) {
                        if (is_type_compound(type)) {
@@ -3804,8 +3754,9 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                }
        } else {
                /* create a declaration type entity */
+               source_position_t const *const pos = env.symbol ? &env.source_position : &specifiers->source_position;
                if (flags & DECL_CREATE_COMPOUND_MEMBER) {
-                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol);
+                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol, pos);
 
                        if (env.symbol != NULL) {
                                if (specifiers->is_inline && is_type_valid(type)) {
@@ -3821,10 +3772,10 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                }
                        }
                } else if (flags & DECL_IS_PARAMETER) {
-                       entity    = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol);
+                       entity    = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol, pos);
                        orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
                } else if (is_type_function(type)) {
-                       entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol);
+                       entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol, pos);
                        entity->function.is_inline      = specifiers->is_inline;
                        entity->function.elf_visibility = default_visibility;
                        entity->function.parameters     = env.parameters;
@@ -3842,7 +3793,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                }
                        }
                } else {
-                       entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol);
+                       entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol, pos);
                        entity->variable.elf_visibility = default_visibility;
                        entity->variable.thread_local   = specifiers->thread_local;
 
@@ -3870,7 +3821,6 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                        }
                }
 
-               entity->base.source_position   = env.symbol != NULL ? env.source_position : specifiers->source_position;
                entity->declaration.type       = orig_type;
                entity->declaration.alignment  = get_type_alignment(orig_type);
                entity->declaration.modifiers  = env.modifiers;
@@ -3888,6 +3838,10 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                handle_entity_attributes(attributes, entity);
        }
 
+       if (entity->kind == ENTITY_FUNCTION && !freestanding) {
+               adapt_special_functions(&entity->function);
+       }
+
        return entity;
 }
 
@@ -3978,7 +3932,7 @@ warn_arg_count:
  */
 static bool is_sym_main(const symbol_t *const sym)
 {
-       return strcmp(sym->string, "main") == 0;
+       return streq(sym->string, "main");
 }
 
 static void error_redefined_as_different_kind(const source_position_t *pos,
@@ -4104,8 +4058,22 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                                goto finish;
                        }
                        if (previous_entity->kind == ENTITY_TYPEDEF) {
-                               /* TODO: C++ allows this for exactly the same type */
-                               errorf(pos, "redefinition of '%N' (declared %P)", entity, ppos);
+                               type_t *const type      = skip_typeref(entity->typedefe.type);
+                               type_t *const prev_type
+                                       = skip_typeref(previous_entity->typedefe.type);
+                               if (c_mode & _CXX) {
+                                       /* C++ allows double typedef if they are identical
+                                        * (after skipping typedefs) */
+                                       if (type == prev_type)
+                                               goto finish;
+                               } else {
+                                       /* GCC extension: redef in system headers is allowed */
+                                       if ((pos->is_system_header || ppos->is_system_header) &&
+                                           types_compatible(type, prev_type))
+                                               goto finish;
+                               }
+                               errorf(pos, "redefinition of '%N' (declared %P)",
+                                      entity, ppos);
                                goto finish;
                        }
 
@@ -4185,7 +4153,7 @@ warn_redundant_declaration: ;
                                                merge_in_attributes(decl, prev_decl->attributes);
                                        } else if (!is_definition        &&
                                                        is_type_valid(prev_type) &&
-                                                       strcmp(ppos->input_name, "<builtin>") != 0) {
+                                                       !pos->is_system_header) {
                                                warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
                                        }
                                } else if (current_function == NULL) {
@@ -4399,12 +4367,10 @@ static void parse_declaration_rest(entity_t *ndeclaration,
                        /* ISO/IEC 14882:1998(E) §8.5.3:3  The initializer can be omitted
                         * [...] where the extern specifier is explicitly used. */
                        declaration_t *decl = &entity->declaration;
-                       if (decl->storage_class != STORAGE_CLASS_EXTERN) {
-                               type_t *type = decl->type;
-                               if (is_type_reference(skip_typeref(type))) {
-                                       source_position_t const *const pos = &entity->base.source_position;
-                                       errorf(pos, "reference '%#N' must be initialized", entity);
-                               }
+                       if (decl->storage_class != STORAGE_CLASS_EXTERN &&
+                           is_type_reference(skip_typeref(decl->type))) {
+                               source_position_t const *const pos = &entity->base.source_position;
+                               errorf(pos, "reference '%#N' must be initialized", entity);
                        }
                }
 
@@ -4417,12 +4383,11 @@ static void parse_declaration_rest(entity_t *ndeclaration,
                ndeclaration = parse_declarator(specifiers, flags);
                rem_anchor_token('=');
        }
-       expect(';', end_error);
+       rem_anchor_token(',');
+       rem_anchor_token(';');
+       expect(';');
 
-end_error:
        anonymous_entity = NULL;
-       rem_anchor_token(';');
-       rem_anchor_token(',');
 }
 
 static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
@@ -4627,10 +4592,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();
@@ -4730,10 +4691,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;
                        }
 
@@ -4749,8 +4712,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
@@ -4803,13 +4766,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) &&
@@ -5008,20 +4971,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:
@@ -5118,8 +5082,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");
@@ -5136,6 +5100,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");
@@ -5319,6 +5284,22 @@ warn_unreachable:
        }
 }
 
+static bool is_main(entity_t *entity)
+{
+       static symbol_t *sym_main = NULL;
+       if (sym_main == NULL) {
+               sym_main = symbol_table_insert("main");
+       }
+
+       if (entity->base.symbol != sym_main)
+               return false;
+       /* must be in outermost scope */
+       if (entity->base.parent_scope != file_scope)
+               return false;
+
+       return true;
+}
+
 static void parse_external_declaration(void)
 {
        /* function-definitions and declarations both start with declaration
@@ -5468,6 +5449,9 @@ static void parse_external_declaration(void)
                        }
                }
 
+               if (is_main(entity) && enable_main_collect2_hack)
+                       prepare_main_collect2(entity);
+
                POP_PARENT();
                assert(current_function == function);
                assert(current_entity   == entity);
@@ -5642,15 +5626,15 @@ static void parse_bitfield_member(entity_t *entity)
 static void parse_compound_declarators(compound_t *compound,
                const declaration_specifiers_t *specifiers)
 {
+       add_anchor_token(';');
+       add_anchor_token(',');
        do {
                entity_t *entity;
 
                if (token.kind == ':') {
                        /* anonymous bitfield */
                        type_t *type = specifiers->type;
-                       entity_t *entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER,
-                                                               NAMESPACE_NORMAL, NULL);
-                       entity->base.source_position               = *HERE;
+                       entity_t *const entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE);
                        entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
                        entity->declaration.storage_class          = STORAGE_CLASS_NONE;
                        entity->declaration.type                   = type;
@@ -5703,6 +5687,8 @@ static void parse_compound_declarators(compound_t *compound,
                                                                token.kind          != ';' ||
                                                                look_ahead(1)->kind != '}') {
                                                        errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
+                                               } else if (compound->members.entities == NULL) {
+                                                       errorf(pos, "flexible array member in otherwise empty struct");
                                                }
                                        }
                                }
@@ -5711,9 +5697,10 @@ static void parse_compound_declarators(compound_t *compound,
                        }
                }
        } while (next_if(','));
-       expect(';', end_error);
+       rem_anchor_token(',');
+       rem_anchor_token(';');
+       expect(';');
 
-end_error:
        anonymous_entity = NULL;
 }
 
@@ -5737,8 +5724,7 @@ static void parse_compound_type_entries(compound_t *compound)
 
                        default:
                                rem_anchor_token('}');
-                               expect('}', end_error);
-end_error:
+                               expect('}');
                                /* §6.7.2.1:7 */
                                compound->complete = true;
                                return;
@@ -6009,8 +5995,7 @@ static expression_t *parse_wide_character_constant(void)
        return literal;
 }
 
-static entity_t *create_implicit_function(symbol_t *symbol,
-               const source_position_t *source_position)
+static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos)
 {
        type_t *ntype                          = allocate_type_zero(TYPE_FUNCTION);
        ntype->function.return_type            = type_int;
@@ -6018,12 +6003,11 @@ static entity_t *create_implicit_function(symbol_t *symbol,
        ntype->function.linkage                = LINKAGE_C;
        type_t *type                           = identify_new_type(ntype);
 
-       entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol);
+       entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol, pos);
        entity->declaration.storage_class          = STORAGE_CLASS_EXTERN;
        entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
        entity->declaration.type                   = type;
        entity->declaration.implicit               = true;
-       entity->base.source_position               = *source_position;
 
        if (current_scope != NULL)
                record_entity(entity, false);
@@ -6149,13 +6133,9 @@ static entity_t *parse_qualified_identifier(void)
 
        entity_t *entity;
        while (true) {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
+               symbol = expect_identifier("while parsing identifier", &pos);
+               if (!symbol)
                        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
-               }
-               symbol = token.identifier.symbol;
-               pos    = *HERE;
-               next_token();
 
                /* lookup entity */
                entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
@@ -6218,7 +6198,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;
@@ -6258,7 +6238,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 */
@@ -6324,7 +6304,7 @@ static expression_t *parse_cast(void)
        type_t *type = parse_typename();
 
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        if (token.kind == '{') {
                return parse_compound_literal(&pos, type);
@@ -6342,8 +6322,6 @@ static expression_t *parse_cast(void)
        }
 
        return cast;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6377,9 +6355,7 @@ static expression_t *parse_statement_expression(void)
        expression->base.type = type;
 
        rem_anchor_token(')');
-       expect(')', end_error);
-
-end_error:
+       expect(')');
        return expression;
 }
 
@@ -6406,9 +6382,8 @@ static expression_t *parse_parenthesized_expression(void)
        expression_t *result = parse_expression();
        result->base.parenthesized = true;
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
-end_error:
        return result;
 }
 
@@ -6476,29 +6451,18 @@ static expression_t *parse_funcdname_keyword(void)
 
 static designator_t *parse_designator(void)
 {
-       designator_t *result    = allocate_ast_zero(sizeof(result[0]));
-       result->source_position = *HERE;
-
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected("while parsing member designator",
-                                    T_IDENTIFIER, NULL);
+       designator_t *const result = allocate_ast_zero(sizeof(result[0]));
+       result->symbol = expect_identifier("while parsing member designator", &result->source_position);
+       if (!result->symbol)
                return NULL;
-       }
-       result->symbol = token.identifier.symbol;
-       next_token();
 
        designator_t *last_designator = result;
        while (true) {
                if (next_if('.')) {
-                       if (token.kind != T_IDENTIFIER) {
-                               parse_error_expected("while parsing member designator",
-                                                    T_IDENTIFIER, NULL);
+                       designator_t *const designator = allocate_ast_zero(sizeof(result[0]));
+                       designator->symbol = expect_identifier("while parsing member designator", &designator->source_position);
+                       if (!designator->symbol)
                                return NULL;
-                       }
-                       designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
-                       designator->source_position = *HERE;
-                       designator->symbol          = token.identifier.symbol;
-                       next_token();
 
                        last_designator->next = designator;
                        last_designator       = designator;
@@ -6510,7 +6474,7 @@ static designator_t *parse_designator(void)
                        designator->source_position = *HERE;
                        designator->array_index     = parse_expression();
                        rem_anchor_token(']');
-                       expect(']', end_error);
+                       expect(']');
                        if (designator->array_index == NULL) {
                                return NULL;
                        }
@@ -6523,8 +6487,6 @@ static designator_t *parse_designator(void)
        }
 
        return result;
-end_error:
-       return NULL;
 }
 
 /**
@@ -6537,15 +6499,15 @@ static expression_t *parse_offsetof(void)
 
        eat(T___builtin_offsetof);
 
-       expect('(', end_error);
+       expect('(');
+       add_anchor_token(')');
        add_anchor_token(',');
        type_t *type = parse_typename();
        rem_anchor_token(',');
-       expect(',', end_error);
-       add_anchor_token(')');
+       expect(',');
        designator_t *designator = parse_designator();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        expression->offsetofe.type       = type;
        expression->offsetofe.designator = designator;
@@ -6564,8 +6526,6 @@ static expression_t *parse_offsetof(void)
        DEL_ARR_F(path.path);
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6577,11 +6537,12 @@ static expression_t *parse_va_start(void)
 
        eat(T___builtin_va_start);
 
-       expect('(', end_error);
+       expect('(');
+       add_anchor_token(')');
        add_anchor_token(',');
        expression->va_starte.ap = parse_assignment_expression();
        rem_anchor_token(',');
-       expect(',', end_error);
+       expect(',');
        expression_t *const expr = parse_assignment_expression();
        if (expr->kind == EXPR_REFERENCE) {
                entity_t *const entity = expr->reference.entity;
@@ -6596,12 +6557,12 @@ static expression_t *parse_va_start(void)
                } else {
                        expression->va_starte.parameter = &entity->variable;
                }
-               expect(')', end_error);
-               return expression;
+       } else {
+               expression = create_error_expression();
        }
-       expect(')', end_error);
-end_error:
-       return create_error_expression();
+       rem_anchor_token(')');
+       expect(')');
+       return expression;
 }
 
 /**
@@ -6613,19 +6574,21 @@ static expression_t *parse_va_arg(void)
 
        eat(T___builtin_va_arg);
 
-       expect('(', end_error);
+       expect('(');
+       add_anchor_token(')');
+       add_anchor_token(',');
        call_argument_t ap;
        ap.expression = parse_assignment_expression();
        expression->va_arge.ap = ap.expression;
        check_call_argument(type_valist, &ap, 1);
 
-       expect(',', end_error);
+       rem_anchor_token(',');
+       expect(',');
        expression->base.type = parse_typename();
-       expect(')', end_error);
+       rem_anchor_token(')');
+       expect(')');
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6637,24 +6600,26 @@ static expression_t *parse_va_copy(void)
 
        eat(T___builtin_va_copy);
 
-       expect('(', end_error);
+       expect('(');
+       add_anchor_token(')');
+       add_anchor_token(',');
        expression_t *dst = parse_assignment_expression();
        assign_error_t error = semantic_assign(type_valist, dst);
        report_assign_error(error, type_valist, dst, "call argument 1",
                            &dst->base.source_position);
        expression->va_copye.dst = dst;
 
-       expect(',', end_error);
+       rem_anchor_token(',');
+       expect(',');
 
        call_argument_t src;
        src.expression = parse_assignment_expression();
        check_call_argument(type_valist, &src, 2);
        expression->va_copye.src = src.expression;
-       expect(')', end_error);
+       rem_anchor_token(')');
+       expect(')');
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6666,16 +6631,14 @@ static expression_t *parse_builtin_constant(void)
 
        eat(T___builtin_constant_p);
 
-       expect('(', end_error);
+       expect('(');
        add_anchor_token(')');
        expression->builtin_constant.value = parse_assignment_expression();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
        expression->base.type = type_int;
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6687,20 +6650,18 @@ static expression_t *parse_builtin_types_compatible(void)
 
        eat(T___builtin_types_compatible_p);
 
-       expect('(', end_error);
+       expect('(');
        add_anchor_token(')');
        add_anchor_token(',');
        expression->builtin_types_compatible.left = parse_typename();
        rem_anchor_token(',');
-       expect(',', end_error);
+       expect(',');
        expression->builtin_types_compatible.right = parse_typename();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
        expression->base.type = type_int;
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6735,11 +6696,15 @@ static expression_t *parse_compare_builtin(void)
        expression->base.source_position = *HERE;
        next_token();
 
-       expect('(', end_error);
+       expect('(');
+       add_anchor_token(')');
+       add_anchor_token(',');
        expression->binary.left = parse_assignment_expression();
-       expect(',', end_error);
+       rem_anchor_token(',');
+       expect(',');
        expression->binary.right = parse_assignment_expression();
-       expect(')', end_error);
+       rem_anchor_token(')');
+       expect(')');
 
        type_t *const orig_type_left  = expression->binary.left->base.type;
        type_t *const orig_type_right = expression->binary.right->base.type;
@@ -6756,8 +6721,6 @@ static expression_t *parse_compare_builtin(void)
        }
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6769,16 +6732,14 @@ static expression_t *parse_assume(void)
 
        eat(T__assume);
 
-       expect('(', end_error);
+       expect('(');
        add_anchor_token(')');
        expression->unary.value = parse_assignment_expression();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        expression->base.type = type_void;
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6798,7 +6759,8 @@ static label_t *get_label(void)
                }
        } else if (label == NULL || label->base.parent_scope != &current_function->parameters) {
                /* There is no matching label in the same function, so create a new one. */
-               label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol);
+               source_position_t const nowhere = { NULL, 0, 0, false };
+               label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol, &nowhere);
                label_push(label);
        }
 
@@ -6853,12 +6815,12 @@ 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);
+       expect(')');
 
-end_error:
        return literal;
 }
 
@@ -6982,8 +6944,7 @@ check_idx:
        arr->base.type = res_type;
 
        rem_anchor_token(']');
-       expect(']', end_error);
-end_error:
+       expect(']');
        return expr;
 }
 
@@ -7008,7 +6969,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
                add_anchor_token(')');
                orig_type = parse_typename();
                rem_anchor_token(')');
-               expect(')', end_error);
+               expect(')');
 
                if (token.kind == '{') {
                        /* It was not sizeof(type) after all.  It is sizeof of an expression
@@ -7036,7 +6997,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) {
@@ -7056,7 +7017,6 @@ typeprop_expression:
                                what, wrong_type, orig_type);
        }
 
-end_error:
        return tp_expression;
 }
 
@@ -7077,12 +7037,9 @@ static expression_t *parse_select_expression(expression_t *addr)
        source_position_t const pos = *HERE;
        next_token();
 
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
+       symbol_t *const symbol = expect_identifier("while parsing select", NULL);
+       if (!symbol)
                return create_error_expression();
-       }
-       symbol_t *symbol = token.identifier.symbol;
-       next_token();
 
        type_t *const orig_type = addr->base.type;
        type_t *const type      = skip_typeref(orig_type);
@@ -7302,7 +7259,7 @@ static expression_t *parse_call_expression(expression_t *expression)
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        if (function_type == NULL)
                return result;
@@ -7351,7 +7308,6 @@ static expression_t *parse_call_expression(expression_t *expression)
                        handle_builtin_argument_restrictions(call);
        }
 
-end_error:
        return result;
 }
 
@@ -7453,8 +7409,7 @@ static expression_t *parse_conditional_expression(expression_t *expression)
                true_expression = parse_expression();
        }
        rem_anchor_token(':');
-       expect(':', end_error);
-end_error:;
+       expect(':');
        expression_t *false_expression =
                parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
 
@@ -7466,16 +7421,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;
@@ -7508,8 +7461,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))) {
@@ -7565,16 +7517,14 @@ static expression_t *parse_builtin_classify_type(void)
 
        eat(T___builtin_classify_type);
 
-       expect('(', end_error);
+       expect('(');
        add_anchor_token(')');
        expression_t *expression = parse_expression();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
        result->classify_type.type_expression = expression;
 
        return result;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -7590,8 +7540,7 @@ static expression_t *parse_delete(void)
 
        if (next_if('[')) {
                result->kind = EXPR_UNARY_DELETE_ARRAY;
-               expect(']', end_error);
-end_error:;
+               expect(']');
        }
 
        expression_t *const value = parse_subexpression(PREC_CAST);
@@ -7603,7 +7552,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");
        }
@@ -7634,8 +7583,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);
                                }
@@ -7658,7 +7606,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);
@@ -8172,7 +8120,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 {
@@ -8527,7 +8475,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 */
@@ -8595,7 +8543,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;
@@ -8866,21 +8814,18 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
 
        while (token.kind == T_STRING_LITERAL || token.kind == '[') {
                asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
-               memset(argument, 0, sizeof(argument[0]));
 
                if (next_if('[')) {
-                       if (token.kind != T_IDENTIFIER) {
-                               parse_error_expected("while parsing asm argument",
-                                                    T_IDENTIFIER, NULL);
+                       add_anchor_token(']');
+                       argument->symbol = expect_identifier("while parsing asm argument", NULL);
+                       rem_anchor_token(']');
+                       expect(']');
+                       if (!argument->symbol)
                                return NULL;
-                       }
-                       argument->symbol = token.identifier.symbol;
-
-                       expect(']', end_error);
                }
 
                argument->constraints = parse_string_literals();
-               expect('(', end_error);
+               expect('(');
                add_anchor_token(')');
                expression_t *expression = parse_expression();
                rem_anchor_token(')');
@@ -8942,7 +8887,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                        mark_vars_read(expression, NULL);
                }
                argument->expression = expression;
-               expect(')', end_error);
+               expect(')');
 
                set_address_taken(expression, true);
 
@@ -8954,8 +8899,6 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
        }
 
        return result;
-end_error:
-       return NULL;
 }
 
 /**
@@ -8993,7 +8936,7 @@ static statement_t *parse_asm_statement(void)
        if (next_if(T_volatile))
                asm_statement->is_volatile = true;
 
-       expect('(', end_error);
+       expect('(');
        add_anchor_token(')');
        if (token.kind != T_STRING_LITERAL) {
                parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
@@ -9024,8 +8967,8 @@ static statement_t *parse_asm_statement(void)
 
 end_of_asm:
        rem_anchor_token(')');
-       expect(')', end_error);
-       expect(';', end_error);
+       expect(')');
+       expect(';');
 
        if (asm_statement->outputs == NULL) {
                /* GCC: An 'asm' instruction without any output operands will be treated
@@ -9034,8 +8977,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)
@@ -9079,8 +9020,24 @@ static statement_t *parse_case_statement(void)
        source_position_t *const pos       = &statement->base.source_position;
 
        eat(T_case);
+       add_anchor_token(':');
+
+       expression_t *expression = parse_expression();
+       type_t *expression_type = expression->base.type;
+       type_t *skipped         = skip_typeref(expression_type);
+       if (!is_type_integer(skipped) && is_type_valid(skipped)) {
+               errorf(pos, "case expression '%E' must have integer type but has type '%T'",
+                      expression, expression_type);
+       }
+
+       type_t *type = expression_type;
+       if (current_switch != NULL) {
+               type_t *switch_type = current_switch->expression->base.type;
+               if (is_type_valid(switch_type)) {
+                       expression = create_implicit_cast(expression, switch_type);
+               }
+       }
 
-       expression_t *const expression   = parse_expression();
        statement->case_label.expression = expression;
        expression_classification_t const expr_class = is_constant_expression(expression);
        if (expr_class != EXPR_CLASS_CONSTANT) {
@@ -9096,7 +9053,15 @@ static statement_t *parse_case_statement(void)
 
        if (GNU_MODE) {
                if (next_if(T_DOTDOTDOT)) {
-                       expression_t *const end_range   = parse_expression();
+                       expression_t *end_range = parse_expression();
+                       expression_type = expression->base.type;
+                       skipped         = skip_typeref(expression_type);
+                       if (!is_type_integer(skipped) && is_type_valid(skipped)) {
+                               errorf(pos, "case expression '%E' must have integer type but has type '%T'",
+                                          expression, expression_type);
+                       }
+
+                       end_range = create_implicit_cast(end_range, type);
                        statement->case_label.end_range = end_range;
                        expression_classification_t const end_class = is_constant_expression(end_range);
                        if (end_class != EXPR_CLASS_CONSTANT) {
@@ -9118,8 +9083,8 @@ static statement_t *parse_case_statement(void)
 
        PUSH_PARENT(statement);
 
-       expect(':', end_error);
-end_error:
+       rem_anchor_token(':');
+       expect(':');
 
        if (current_switch != NULL) {
                if (! statement->case_label.is_bad) {
@@ -9165,8 +9130,7 @@ static statement_t *parse_default_statement(void)
 
        PUSH_PARENT(statement);
 
-       expect(':', end_error);
-end_error:
+       expect(':');
 
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
@@ -9243,6 +9207,20 @@ 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('(');
+       add_anchor_token(')');
+       expression_t *const expr = parse_expression();
+       mark_vars_read(expr, NULL);
+       rem_anchor_token(')');
+       expect(')');
+       return expr;
+}
+
 /**
  * Parse an if statement.
  */
@@ -9253,24 +9231,16 @@ static statement_t *parse_if(void)
        eat(T_if);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->ifs.scope);
 
-       add_anchor_token('{');
+       add_anchor_token(T_else);
 
-       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);
        statement_t *const true_stmt = parse_inner_statement();
        statement->ifs.true_statement = true_stmt;
        rem_anchor_token(T_else);
@@ -9293,6 +9263,7 @@ end_error:
                warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
        }
 
+       POP_SCOPE();
        POP_PARENT();
        return statement;
 }
@@ -9350,11 +9321,9 @@ static statement_t *parse_switch(void)
        eat(T_switch);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->switchs.scope);
 
-       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);
@@ -9367,8 +9336,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;
@@ -9380,11 +9347,9 @@ static statement_t *parse_switch(void)
        }
        check_enum_cases(&statement->switchs);
 
+       POP_SCOPE();
        POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT();
-       return create_error_statement();
 }
 
 static statement_t *parse_loop_body(statement_t *const loop)
@@ -9408,25 +9373,19 @@ static statement_t *parse_while(void)
        eat(T_while);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->whiles.scope);
 
-       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_SCOPE();
        POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT();
-       return create_error_statement();
 }
 
 /**
@@ -9439,29 +9398,23 @@ static statement_t *parse_do(void)
        eat(T_do);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->do_while.scope);
 
        add_anchor_token(T_while);
        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);
+       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(';');
 
+       POP_SCOPE();
        POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT();
-       return create_error_statement();
 }
 
 /**
@@ -9473,11 +9426,11 @@ static statement_t *parse_for(void)
 
        eat(T_for);
 
-       expect('(', end_error1);
-       add_anchor_token(')');
-
        PUSH_PARENT(statement);
-       PUSH_SCOPE(&statement->fors.scope);
+       PUSH_SCOPE_STATEMENT(&statement->fors.scope);
+
+       expect('(');
+       add_anchor_token(')');
 
        PUSH_EXTENSION();
 
@@ -9493,7 +9446,7 @@ 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(';');
        }
 
        POP_EXTENSION();
@@ -9508,7 +9461,7 @@ static statement_t *parse_for(void)
                mark_vars_read(cond, NULL);
                rem_anchor_token(';');
        }
-       expect(';', end_error2);
+       expect(';');
        if (token.kind != ')') {
                expression_t *const step = parse_expression();
                statement->fors.step = step;
@@ -9517,22 +9470,13 @@ 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(')');
        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();
 }
 
 /**
@@ -9540,10 +9484,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);
 
@@ -9561,27 +9507,29 @@ 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();
+                       statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
+               }
        }
 
-       /* remember the goto's in a list for later checking */
-       *goto_anchor = &statement->gotos;
-       goto_anchor  = &statement->gotos.next;
-
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9597,9 +9545,7 @@ static statement_t *parse_continue(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
 
        eat(T_continue);
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9615,9 +9561,7 @@ static statement_t *parse_break(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
 
        eat(T_break);
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9633,9 +9577,7 @@ static statement_t *parse_leave_statement(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
 
        eat(T___leave);
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9690,6 +9632,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.
  */
@@ -9712,24 +9663,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);
@@ -9744,20 +9685,13 @@ 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;
 
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9795,9 +9729,7 @@ static statement_t *parse_expression_statement(void)
        statement->expression.expression = expr;
        mark_vars_read(expr, ENT_ANY);
 
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9820,10 +9752,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);
@@ -9833,18 +9762,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)
@@ -9865,20 +9787,18 @@ static statement_t *parse_local_label_declaration(void)
        entity_t *end     = NULL;
        entity_t **anchor = &begin;
        do {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing local label declaration",
-                               T_IDENTIFIER, NULL);
+               source_position_t pos;
+               symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
+               if (!symbol)
                        goto end_error;
-               }
-               symbol_t *symbol = token.identifier.symbol;
+
                entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
                if (entity != NULL && entity->base.parent_scope == current_scope) {
                        source_position_t const *const ppos = &entity->base.source_position;
-                       errorf(HERE, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
+                       errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                } else {
-                       entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol);
-                       entity->base.parent_scope    = current_scope;
-                       entity->base.source_position = token.base.source_position;
+                       entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
+                       entity->base.parent_scope = current_scope;
 
                        *anchor = entity;
                        anchor  = &entity->base.next;
@@ -9886,9 +9806,8 @@ static statement_t *parse_local_label_declaration(void)
 
                        environment_push(entity);
                }
-               next_token();
        } while (next_if(','));
-       expect(';', end_error);
+       expect(';');
 end_error:
        statement->declaration.declarations_begin = begin;
        statement->declaration.declarations_end   = end;
@@ -9919,9 +9838,8 @@ static void parse_namespace_definition(void)
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
-               entity->base.source_position = token.base.source_position;
-               entity->base.parent_scope    = current_scope;
+               entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol, HERE);
+               entity->base.parent_scope = current_scope;
        }
 
        if (token.kind == '=') {
@@ -9937,11 +9855,12 @@ static void parse_namespace_definition(void)
        entity_t     *old_current_entity = current_entity;
        current_entity = entity;
 
-       expect('{', end_error);
+       add_anchor_token('}');
+       expect('{');
        parse_externals();
-       expect('}', end_error);
+       rem_anchor_token('}');
+       expect('}');
 
-end_error:
        assert(current_entity == entity);
        current_entity = old_current_entity;
        POP_SCOPE();
@@ -9954,10 +9873,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;
@@ -10028,14 +9945,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;
 }
@@ -10080,6 +9992,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);
@@ -10163,18 +10076,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) {
@@ -10185,13 +10090,9 @@ 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('}');
 
        /* look over all statements again to produce no effect warnings */
        if (is_warn_on(WARN_UNUSED_VALUE)) {
@@ -10211,7 +10112,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);
@@ -10292,6 +10192,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('*');
@@ -10348,16 +10249,20 @@ static void parse_global_asm(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
 
        eat(T_asm);
-       expect('(', end_error);
+       add_anchor_token(';');
+       add_anchor_token(')');
+       add_anchor_token(T_STRING_LITERAL);
+       expect('(');
 
+       rem_anchor_token(T_STRING_LITERAL);
        statement->asms.asm_text = parse_string_literals();
        statement->base.next     = unit->global_asm;
        unit->global_asm         = statement;
 
-       expect(')', end_error);
-       expect(';', end_error);
-
-end_error:;
+       rem_anchor_token(')');
+       expect(')');
+       rem_anchor_token(';');
+       expect(';');
 }
 
 static void parse_linkage_specification(void)
@@ -10369,9 +10274,9 @@ static void parse_linkage_specification(void)
 
        linkage_kind_t old_linkage = current_linkage;
        linkage_kind_t new_linkage;
-       if (strcmp(linkage, "C") == 0) {
+       if (streq(linkage, "C")) {
                new_linkage = LINKAGE_C;
-       } else if (strcmp(linkage, "C++") == 0) {
+       } else if (streq(linkage, "C++")) {
                new_linkage = LINKAGE_CXX;
        } else {
                errorf(&pos, "linkage string \"%s\" not recognized", linkage);
@@ -10381,12 +10286,11 @@ static void parse_linkage_specification(void)
 
        if (next_if('{')) {
                parse_externals();
-               expect('}', end_error);
+               expect('}');
        } else {
                parse_external();
        }
 
-end_error:
        assert(current_linkage == new_linkage);
        current_linkage = old_linkage;
 }
@@ -10569,6 +10473,8 @@ static void complete_incomplete_arrays(void)
 
 void prepare_main_collect2(entity_t *entity)
 {
+       PUSH_SCOPE(&entity->function.statement->compound.scope);
+
        // create call to __main
        symbol_t *symbol         = symbol_table_insert("__main");
        entity_t *subsubmain_ent
@@ -10595,6 +10501,8 @@ void prepare_main_collect2(entity_t *entity)
 
        expr_statement->base.next = compounds->statements;
        compounds->statements     = expr_statement;
+
+       POP_SCOPE();
 }
 
 void parse(void)