Remove the typedef for the non-existent type_argument_t.
[cparser] / parser.c
index c59790e..04adbc1 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"
@@ -36,7 +37,7 @@
 #include "entity_t.h"
 #include "attribute_t.h"
 #include "lang_features.h"
-#include "walk_statements.h"
+#include "walk.h"
 #include "warning.h"
 #include "printer.h"
 #include "adt/bitfiddle.h"
@@ -89,20 +90,17 @@ static scope_t             *current_scope     = NULL;
 /** Point to the current function declaration if inside a function. */
 static function_t          *current_function  = NULL;
 static entity_t            *current_entity    = NULL;
-static entity_t            *current_init_decl = NULL;
 static switch_statement_t  *current_switch    = NULL;
 static statement_t         *current_loop      = NULL;
 static statement_t         *current_parent    = NULL;
 static ms_try_statement_t  *current_try       = NULL;
-static linkage_kind_t       current_linkage   = LINKAGE_INVALID;
+static linkage_kind_t       current_linkage;
 static goto_statement_t    *goto_first        = NULL;
 static goto_statement_t   **goto_anchor       = NULL;
 static label_statement_t   *label_first       = NULL;
 static label_statement_t  **label_anchor      = NULL;
 /** current translation unit. */
 static translation_unit_t  *unit              = NULL;
-/** true if we are in a type property context (evaluation only for type) */
-static bool                 in_type_prop      = false;
 /** true if we are in an __extension__ context. */
 static bool                 in_gcc_extension  = false;
 static struct obstack       temp_obst;
@@ -111,19 +109,43 @@ static declaration_t      **incomplete_arrays;
 static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 
 
-#define PUSH_PARENT(stmt)                          \
-       statement_t *const prev_parent = current_parent; \
-       ((void)(current_parent = (stmt)))
-#define POP_PARENT ((void)(current_parent = prev_parent))
+#define PUSH_CURRENT_ENTITY(entity) \
+       entity_t *const new_current_entity = (entity); \
+       entity_t *const old_current_entity = current_entity; \
+       ((void)(current_entity = new_current_entity))
+#define POP_CURRENT_ENTITY() (assert(current_entity == new_current_entity), (void)(current_entity = old_current_entity))
+
+#define PUSH_PARENT(stmt) \
+       statement_t *const new_parent = (stmt); \
+       statement_t *const old_parent = current_parent; \
+       ((void)(current_parent = new_parent))
+#define POP_PARENT() (assert(current_parent == new_parent), (void)(current_parent = old_parent))
+
+#define PUSH_SCOPE(scope) \
+       size_t   const top       = environment_top(); \
+       scope_t *const new_scope = (scope); \
+       scope_t *const old_scope = (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; \
+       bool const old_gcc_extension = in_gcc_extension; \
+       while (next_if(T___extension__)) { \
+               in_gcc_extension = true; \
+       } \
+       do {} while (0)
+#define POP_EXTENSION() \
+       ((void)(in_gcc_extension = old_gcc_extension))
 
 /** special symbol used for anonymous entities. */
 static symbol_t *sym_anonymous = NULL;
 
 /** The token anchor set */
-static unsigned char token_anchor_set[T_LAST_TOKEN];
+static unsigned short token_anchor_set[T_LAST_TOKEN];
 
 /** The current source position. */
-#define HERE (&token.source_position)
+#define HERE (&token.base.source_position)
 
 /** true if we are in GCC mode. */
 #define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
@@ -226,10 +248,7 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_ANDAND:                    \
        case T_CHARACTER_CONSTANT:        \
        case T_FLOATINGPOINT:             \
-       case T_FLOATINGPOINT_HEXADECIMAL: \
        case T_INTEGER:                   \
-       case T_INTEGER_HEXADECIMAL:       \
-       case T_INTEGER_OCTAL:             \
        case T_MINUSMINUS:                \
        case T_PLUSPLUS:                  \
        case T_STRING_LITERAL:            \
@@ -269,25 +288,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_INVALID]     = sizeof(invalid_statement_t),
-               [STATEMENT_EMPTY]       = sizeof(empty_statement_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);
@@ -302,15 +322,12 @@ static size_t get_statement_struct_size(statement_kind_t kind)
 static size_t get_expression_struct_size(expression_kind_t kind)
 {
        static const size_t sizes[] = {
-               [EXPR_INVALID]                    = sizeof(expression_base_t),
+               [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),
-               [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t),
                [EXPR_LITERAL_FLOATINGPOINT]      = sizeof(literal_expression_t),
-               [EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL] = sizeof(literal_expression_t),
                [EXPR_LITERAL_CHARACTER]          = sizeof(literal_expression_t),
                [EXPR_LITERAL_WIDE_CHARACTER]     = sizeof(literal_expression_t),
                [EXPR_STRING_LITERAL]             = sizeof(string_literal_expression_t),
@@ -358,7 +375,7 @@ static statement_t *allocate_statement_zero(statement_kind_t kind)
 
        res->base.kind            = kind;
        res->base.parent          = current_parent;
-       res->base.source_position = token.source_position;
+       res->base.source_position = token.base.source_position;
        return res;
 }
 
@@ -375,7 +392,7 @@ static expression_t *allocate_expression_zero(expression_kind_t kind)
 
        res->base.kind            = kind;
        res->base.type            = type_error_type;
-       res->base.source_position = token.source_position;
+       res->base.source_position = token.base.source_position;
        return res;
 }
 
@@ -383,17 +400,19 @@ static expression_t *allocate_expression_zero(expression_kind_t kind)
  * Creates a new invalid expression at the source position
  * of the current token.
  */
-static expression_t *create_invalid_expression(void)
+static expression_t *create_error_expression(void)
 {
-       return allocate_expression_zero(EXPR_INVALID);
+       expression_t *expression = allocate_expression_zero(EXPR_ERROR);
+       expression->base.type = type_error_type;
+       return expression;
 }
 
 /**
  * Creates a new invalid statement.
  */
-static statement_t *create_invalid_statement(void)
+static statement_t *create_error_statement(void)
 {
-       return allocate_statement_zero(STATEMENT_INVALID);
+       return allocate_statement_zero(STATEMENT_ERROR);
 }
 
 /**
@@ -468,9 +487,9 @@ static inline void next_token(void)
 #endif
 }
 
-static inline bool next_if(int const type)
+static inline bool next_if(token_kind_t const type)
 {
-       if (token.type == type) {
+       if (token.kind == type) {
                next_token();
                return true;
        } else {
@@ -491,60 +510,28 @@ static inline const token_t *look_ahead(size_t num)
 /**
  * Adds a token type to the token type anchor set (a multi-set).
  */
-static void add_anchor_token(int token_type)
-{
-       assert(0 <= token_type && token_type < T_LAST_TOKEN);
-       ++token_anchor_set[token_type];
-}
-
-/**
- * Set the number of tokens types of the given type
- * to zero and return the old count.
- */
-static int save_and_reset_anchor_state(int token_type)
-{
-       assert(0 <= token_type && token_type < T_LAST_TOKEN);
-       int count = token_anchor_set[token_type];
-       token_anchor_set[token_type] = 0;
-       return count;
-}
-
-/**
- * Restore the number of token types to the given count.
- */
-static void restore_anchor_state(int token_type, int count)
+static void add_anchor_token(token_kind_t const token_kind)
 {
-       assert(0 <= token_type && token_type < T_LAST_TOKEN);
-       token_anchor_set[token_type] = count;
+       assert(token_kind < T_LAST_TOKEN);
+       ++token_anchor_set[token_kind];
 }
 
 /**
  * Remove a token type from the token type anchor set (a multi-set).
  */
-static void rem_anchor_token(int token_type)
-{
-       assert(0 <= token_type && token_type < T_LAST_TOKEN);
-       assert(token_anchor_set[token_type] != 0);
-       --token_anchor_set[token_type];
-}
-
-/**
- * Return true if the token type of the current token is
- * in the anchor set.
- */
-static bool at_anchor(void)
+static void rem_anchor_token(token_kind_t const token_kind)
 {
-       if (token.type < 0)
-               return false;
-       return token_anchor_set[token.type];
+       assert(token_kind < T_LAST_TOKEN);
+       assert(token_anchor_set[token_kind] != 0);
+       --token_anchor_set[token_kind];
 }
 
 /**
  * Eat tokens until a matching token type is found.
  */
-static void eat_until_matching_token(int type)
+static void eat_until_matching_token(token_kind_t const type)
 {
-       int end_token;
+       token_kind_t end_token;
        switch (type) {
                case '(': end_token = ')';  break;
                case '{': end_token = '}';  break;
@@ -555,11 +542,11 @@ static void eat_until_matching_token(int type)
        unsigned parenthesis_count = 0;
        unsigned brace_count       = 0;
        unsigned bracket_count     = 0;
-       while (token.type        != end_token ||
+       while (token.kind        != end_token ||
               parenthesis_count != 0         ||
               brace_count       != 0         ||
               bracket_count     != 0) {
-               switch (token.type) {
+               switch (token.kind) {
                case T_EOF: return;
                case '(': ++parenthesis_count; break;
                case '{': ++brace_count;       break;
@@ -579,7 +566,7 @@ static void eat_until_matching_token(int type)
                        if (bracket_count > 0)
                                --bracket_count;
 check_stop:
-                       if (token.type        == end_token &&
+                       if (token.kind        == end_token &&
                            parenthesis_count == 0         &&
                            brace_count       == 0         &&
                            bracket_count     == 0)
@@ -598,9 +585,9 @@ check_stop:
  */
 static void eat_until_anchor(void)
 {
-       while (token_anchor_set[token.type] == 0) {
-               if (token.type == '(' || token.type == '{' || token.type == '[')
-                       eat_until_matching_token(token.type);
+       while (token_anchor_set[token.kind] == 0) {
+               if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+                       eat_until_matching_token(token.kind);
                next_token();
        }
 }
@@ -614,7 +601,7 @@ static void eat_block(void)
        next_if('}');
 }
 
-#define eat(token_type) (assert(token.type == (token_type)), next_token())
+#define eat(token_kind) (assert(token.kind == (token_kind)), next_token())
 
 /**
  * Report a parse error because an expected token was not found.
@@ -646,21 +633,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.type != (expected))) {         \
-                       parse_error_expected(NULL, (expected), NULL); \
-                       add_anchor_token(expected);                   \
-                       eat_until_anchor();                           \
-                       next_if((expected));                          \
-                       rem_anchor_token(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
@@ -691,7 +694,6 @@ static void scope_pop(scope_t *old_scope)
 static entity_t *get_entity(const symbol_t *const symbol,
                             namespace_tag_t namespc)
 {
-       assert(namespc != NAMESPACE_INVALID);
        entity_t *entity = symbol->entity;
        for (; entity != NULL; entity = entity->base.symbol_next) {
                if ((namespace_tag_t)entity->base.namespc == namespc)
@@ -724,7 +726,7 @@ static void stack_push(stack_entry_t **stack_ptr, entity_t *entity)
 {
        symbol_t           *symbol  = entity->base.symbol;
        entity_namespace_t  namespc = entity->base.namespc;
-       assert(namespc != NAMESPACE_INVALID);
+       assert(namespc != 0);
 
        /* replace/add entity into entity list of the symbol */
        entity_t **anchor;
@@ -838,22 +840,11 @@ static void label_pop_to(size_t new_top)
        stack_pop_to(&label_stack, new_top);
 }
 
-static int get_akind_rank(atomic_type_kind_t akind)
-{
-       return (int) akind;
-}
-
-/**
- * Return the type rank for an atomic type.
- */
-static int get_rank(const type_t *type)
+static atomic_type_kind_t get_akind(const type_t *type)
 {
-       assert(!is_typeref(type));
-       if (type->kind == TYPE_ENUM)
-               return get_akind_rank(type->enumt.akind);
-
-       assert(type->kind == TYPE_ATOMIC);
-       return get_akind_rank(type->atomic.akind);
+       assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX
+              || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM);
+       return type->atomic.akind;
 }
 
 /**
@@ -864,32 +855,12 @@ static int get_rank(const type_t *type)
  */
 static type_t *promote_integer(type_t *type)
 {
-       if (type->kind == TYPE_BITFIELD)
-               type = type->bitfield.base_type;
-
-       if (get_rank(type) < get_akind_rank(ATOMIC_TYPE_INT))
+       if (get_akind_rank(get_akind(type)) < get_akind_rank(ATOMIC_TYPE_INT))
                type = type_int;
 
        return type;
 }
 
-/**
- * Create a cast expression.
- *
- * @param expression  the expression to cast
- * @param dest_type   the destination type
- */
-static expression_t *create_cast_expression(expression_t *expression,
-                                            type_t *dest_type)
-{
-       expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST_IMPLICIT);
-
-       cast->unary.value = expression;
-       cast->base.type   = dest_type;
-
-       return cast;
-}
-
 /**
  * Check if a given expression represents a null pointer constant.
  *
@@ -898,8 +869,7 @@ static expression_t *create_cast_expression(expression_t *expression,
 static bool is_null_pointer_constant(const expression_t *expression)
 {
        /* skip void* cast */
-       if (expression->kind == EXPR_UNARY_CAST ||
-                       expression->kind == EXPR_UNARY_CAST_IMPLICIT) {
+       if (expression->kind == EXPR_UNARY_CAST) {
                type_t *const type = skip_typeref(expression->base.type);
                if (types_compatible(type, type_void_ptr))
                        expression = expression->unary.value;
@@ -929,7 +899,12 @@ static expression_t *create_implicit_cast(expression_t *expression,
        if (source_type == dest_type)
                return expression;
 
-       return create_cast_expression(expression, dest_type);
+       expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+       cast->unary.value   = expression;
+       cast->base.type     = dest_type;
+       cast->base.implicit = true;
+
+       return cast;
 }
 
 typedef enum assign_error_t {
@@ -1009,10 +984,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;
                        }
@@ -1069,36 +1044,20 @@ static void warn_string_concat(const source_position_t *pos)
 
 static string_t parse_string_literals(void)
 {
-       assert(token.type == T_STRING_LITERAL);
-       string_t result = token.literal;
+       assert(token.kind == T_STRING_LITERAL);
+       string_t result = token.string.string;
 
        next_token();
 
-       while (token.type == T_STRING_LITERAL) {
-               warn_string_concat(&token.source_position);
-               result = concat_strings(&result, &token.literal);
+       while (token.kind == T_STRING_LITERAL) {
+               warn_string_concat(&token.base.source_position);
+               result = concat_strings(&result, &token.string.string);
                next_token();
        }
 
        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));
@@ -1139,13 +1098,13 @@ static attribute_argument_t *parse_attribute_arguments(void)
 {
        attribute_argument_t  *first  = NULL;
        attribute_argument_t **anchor = &first;
-       if (token.type != ')') do {
+       if (token.kind != ')') do {
                attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument));
 
                /* is it an identifier */
-               if (token.type == T_IDENTIFIER
-                               && (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) {
-                       symbol_t *symbol   = token.symbol;
+               if (token.kind == T_IDENTIFIER
+                               && (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
+                       symbol_t *symbol   = token.identifier.symbol;
                        argument->kind     = ATTRIBUTE_ARGUMENT_SYMBOL;
                        argument->v.symbol = symbol;
                        next_token();
@@ -1161,12 +1120,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;
 }
 
@@ -1174,52 +1128,25 @@ 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)
 {
-       switch(token.type) {
-       case T_IDENTIFIER:
-               return token.symbol;
-       case T_auto:
-       case T_char:
-       case T_double:
-       case T_enum:
-       case T_extern:
-       case T_float:
-       case T_int:
-       case T_long:
-       case T_register:
-       case T_short:
-       case T_static:
-       case T_struct:
-       case T_union:
-       case T_unsigned:
-       case T_void:
-       case T_bool:
-       case T__Bool:
-       case T_class:
-       case T_explicit:
-       case T_export:
-       case T_wchar_t:
-       case T_const:
-       case T_signed:
-       case T___real__:
-       case T___imag__:
-       case T_restrict:
-       case T_volatile:
-       case T_inline:
-               /* maybe we need more tokens ... add them on demand */
-               return get_token_symbol(&token);
-       default:
+       switch(token.kind) {
+       case T_CHARACTER_CONSTANT:
+       case T_EOF:
+       case T_FLOATINGPOINT:
+       case T_INTEGER:
+       case T_STRING_LITERAL:
+       case T_WIDE_CHARACTER_CONSTANT:
+       case T_WIDE_STRING_LITERAL:
                return NULL;
+
+       default:
+               return token.identifier.symbol;
        }
 }
 
@@ -1243,8 +1170,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;
        }
 
@@ -1264,21 +1190,23 @@ static attribute_t *parse_attribute_gnu(void)
        attribute_t **anchor = &first;
 
        eat(T___attribute__);
-       expect('(', end_error);
-       expect('(', end_error);
+       expect('(');
+       expect('(');
 
-       if (token.type != ')') do {
+       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;
 }
 
@@ -1291,7 +1219,7 @@ static attribute_t *parse_attributes(attribute_t *first)
                        anchor = &(*anchor)->next;
 
                attribute_t *attribute;
-               switch (token.type) {
+               switch (token.kind) {
                case T___attribute__:
                        attribute = parse_attribute_gnu();
                        if (attribute == NULL)
@@ -1361,19 +1289,17 @@ static entity_t *determine_lhs_ent(expression_t *const expr,
                                ent     = determine_lhs_ent(ref, lhs_ent);
                                lhs_ent = ent;
                        } else {
-                               mark_vars_read(expr->select.compound, lhs_ent);
+                               mark_vars_read(ref, lhs_ent);
                        }
                        mark_vars_read(expr->array_access.index, lhs_ent);
                        return ent;
                }
 
                case EXPR_SELECT: {
-                       if (is_type_compound(skip_typeref(expr->base.type))) {
+                       mark_vars_read(expr->select.compound, lhs_ent);
+                       if (is_type_compound(skip_typeref(expr->base.type)))
                                return determine_lhs_ent(expr->select.compound, lhs_ent);
-                       } else {
-                               mark_vars_read(expr->select.compound, lhs_ent);
-                               return NULL;
-                       }
+                       return NULL;
                }
 
                case EXPR_UNARY_DEREFERENCE: {
@@ -1450,10 +1376,13 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
                        return;
 
                case EXPR_ARRAY_ACCESS: {
+                       mark_vars_read(expr->array_access.index, lhs_ent);
                        expression_t *const ref = expr->array_access.array_ref;
+                       if (!is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) {
+                               if (lhs_ent == ENT_ANY)
+                                       lhs_ent = NULL;
+                       }
                        mark_vars_read(ref, lhs_ent);
-                       lhs_ent = determine_lhs_ent(ref, lhs_ent);
-                       mark_vars_read(expr->array_access.index, lhs_ent);
                        return;
                }
 
@@ -1467,7 +1396,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;
 
@@ -1492,7 +1421,6 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
                case EXPR_UNARY_POSTFIX_DECREMENT:
                case EXPR_UNARY_PREFIX_INCREMENT:
                case EXPR_UNARY_PREFIX_DECREMENT:
-               case EXPR_UNARY_CAST_IMPLICIT:
                case EXPR_UNARY_ASSUME:
 unary:
                        mark_vars_read(expr->unary.value, lhs_ent);
@@ -1549,9 +1477,8 @@ unary:
                        determine_lhs_ent(expr->va_starte.ap, lhs_ent);
                        return;
 
-               EXPR_LITERAL_CASES
-               case EXPR_UNKNOWN:
-               case EXPR_INVALID:
+               case EXPR_LITERAL_CASES:
+               case EXPR_ERROR:
                case EXPR_STRING_LITERAL:
                case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO init?
@@ -1564,7 +1491,7 @@ unary:
                case EXPR_OFFSETOF:
                case EXPR_STATEMENT: // TODO
                case EXPR_LABEL_ADDRESS:
-               case EXPR_REFERENCE_ENUM_VALUE:
+               case EXPR_ENUM_CONSTANT:
                        return;
        }
 
@@ -1578,30 +1505,26 @@ static designator_t *parse_designation(void)
 
        for (;;) {
                designator_t *designator;
-               switch (token.type) {
+               switch (token.kind) {
                case '[':
                        designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = token.source_position;
+                       designator->source_position = token.base.source_position;
                        next_token();
                        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.source_position;
+                       designator->source_position = token.base.source_position;
                        next_token();
-                       if (token.type != 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.symbol;
-                       next_token();
                        break;
                default:
-                       expect('=', end_error);
+                       expect('=');
                        return result;
                }
 
@@ -1609,8 +1532,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,
@@ -1694,15 +1615,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.
  *
@@ -1713,17 +1625,17 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 {
        /* there might be extra {} hierarchies */
        int braces = 0;
-       if (token.type == '{') {
+       if (token.kind == '{') {
                warningf(WARN_OTHER, HERE, "extra curly braces around scalar initializer");
                do {
                        eat('{');
                        ++braces;
-               } while (token.type == '{');
+               } while (token.kind == '{');
        }
 
        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);
@@ -1742,7 +1654,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
        bool additional_warning_displayed = false;
        while (braces > 0) {
                next_if(',');
-               if (token.type != '}') {
+               if (token.kind != '}') {
                        if (!additional_warning_displayed) {
                                warningf(WARN_OTHER, HERE, "additional elements in scalar initializer");
                                additional_warning_displayed = true;
@@ -1846,11 +1758,10 @@ static void descend_into_subtype(type_path_t *path)
        top->type              = top_type;
 
        if (is_type_compound(top_type)) {
-               compound_t *compound  = top_type->compound.compound;
-               entity_t   *entry     = compound->members.entities;
+               compound_t *const compound = top_type->compound.compound;
+               entity_t   *const entry    = skip_unnamed_bitfields(compound->members.entities);
 
                if (entry != NULL) {
-                       assert(entry->kind == ENTITY_COMPOUND_MEMBER);
                        top->v.compound_entry = &entry->declaration;
                        path->top_type = entry->declaration.type;
                } else {
@@ -1927,14 +1838,11 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                        return false;
                                }
                                assert(iter->kind == ENTITY_COMPOUND_MEMBER);
-                               if (used_in_offsetof) {
-                                       type_t *real_type = skip_typeref(iter->declaration.type);
-                                       if (real_type->kind == TYPE_BITFIELD) {
-                                               errorf(&designator->source_position,
-                                                      "offsetof designator '%Y' must not specify bitfield",
-                                                      symbol);
-                                               return false;
-                                       }
+                               if (used_in_offsetof && iter->compound_member.bitfield) {
+                                       errorf(&designator->source_position,
+                                                  "offsetof designator '%Y' must not specify bitfield",
+                                                  symbol);
+                                       return false;
                                }
 
                                top->type             = orig_type;
@@ -1993,7 +1901,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
        } else if (is_type_struct(type)) {
                declaration_t *entry = top->v.compound_entry;
 
-               entity_t *next_entity = entry->base.next;
+               entity_t *const next_entity = skip_unnamed_bitfields(entry->base.next);
                if (next_entity != NULL) {
                        assert(is_declaration(next_entity));
                        entry = &next_entity->declaration;
@@ -2038,10 +1946,10 @@ static void skip_initializers(void)
 {
        next_if('{');
 
-       while (token.type != '}') {
-               if (token.type == T_EOF)
+       while (token.kind != '}') {
+               if (token.kind == T_EOF)
                        return;
-               if (token.type == '{') {
+               if (token.kind == '{') {
                        eat_block();
                        continue;
                }
@@ -2063,7 +1971,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                type_t *outer_type, size_t top_path_level,
                parse_initializer_env_t *env)
 {
-       if (token.type == '}') {
+       if (token.kind == '}') {
                /* empty initializer */
                return create_empty_initializer();
        }
@@ -2081,14 +1989,14 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
 
        while (true) {
                designator_t *designator = NULL;
-               if (token.type == '.' || token.type == '[') {
+               if (token.kind == '.' || token.kind == '[') {
                        designator = parse_designation();
                        goto finish_designator;
-               } else if (token.type == T_IDENTIFIER && look_ahead(1)->type == ':') {
+               } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') {
                        /* GNU-style designator ("identifier: value") */
                        designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = token.source_position;
-                       designator->symbol          = token.symbol;
+                       designator->source_position = token.base.source_position;
+                       designator->symbol          = token.identifier.symbol;
                        eat(T_IDENTIFIER);
                        eat(':');
 
@@ -2111,7 +2019,7 @@ finish_designator:
 
                initializer_t *sub;
 
-               if (token.type == '{') {
+               if (token.kind == '{') {
                        if (type != NULL && is_type_scalar(type)) {
                                sub = parse_scalar_initializer(type, env->must_be_constant);
                        } else {
@@ -2134,20 +2042,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);
@@ -2179,7 +2086,7 @@ finish_designator:
                                sub = initializer_from_expression(outer_type, expression);
                                if (sub != NULL) {
                                        next_if(',');
-                                       if (token.type != '}') {
+                                       if (token.kind != '}') {
                                                warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type);
                                        }
                                        /* TODO: eat , ... */
@@ -2224,11 +2131,13 @@ finish_designator:
                ARR_APP1(initializer_t*, initializers, sub);
 
 error_parse_next:
-               if (token.type == '}') {
+               if (token.kind == '}') {
                        break;
                }
-               expect(',', end_error);
-               if (token.type == '}') {
+               add_anchor_token('}');
+               expect(',');
+               rem_anchor_token('}');
+               if (token.kind == '}') {
                        break;
                }
 
@@ -2287,7 +2196,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
 
        if (is_type_scalar(type)) {
                result = parse_scalar_initializer(type, env->must_be_constant);
-       } else if (token.type == '{') {
+       } else if (token.kind == '{') {
                eat('{');
 
                type_path_t path;
@@ -2304,8 +2213,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 */
@@ -2374,31 +2282,31 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        entity_t    *entity     = NULL;
        attribute_t *attributes = NULL;
 
-       if (token.type == T___attribute__) {
+       if (token.kind == T___attribute__) {
                attributes = parse_attributes(NULL);
        }
 
        entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
-       if (token.type == T_IDENTIFIER) {
+       if (token.kind == T_IDENTIFIER) {
                /* the compound has a name, check if we have seen it already */
-               symbol = token.symbol;
+               symbol = token.identifier.symbol;
                entity = get_tag(symbol, kind);
                next_token();
 
                if (entity != NULL) {
                        if (entity->base.parent_scope != current_scope &&
-                           (token.type == '{' || token.type == ';')) {
+                           (token.kind == '{' || token.kind == ';')) {
                                /* we're in an inner scope and have a definition. Shadow
                                 * existing definition in outer scope */
                                entity = NULL;
-                       } else if (entity->compound.complete && token.type == '{') {
+                       } else if (entity->compound.complete && token.kind == '{') {
                                source_position_t const *const ppos = &entity->base.source_position;
                                errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                                /* clear members in the hope to avoid further errors */
                                entity->compound.members.entities = NULL;
                        }
                }
-       } else if (token.type != '{') {
+       } else if (token.kind != '{') {
                char const *const msg =
                        is_struct ? "while parsing struct type specifier" :
                                    "while parsing union type specifier";
@@ -2408,17 +2316,16 @@ 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);
                }
                append_entity(current_scope, entity);
        }
 
-       if (token.type == '{') {
+       if (token.kind == '{') {
                parse_compound_type_entries(&entity->compound);
 
                /* ISO/IEC 14882:1998(E) Â§7.1.3:5 */
@@ -2439,25 +2346,21 @@ static void parse_enum_entries(type_t *const enum_type)
 {
        eat('{');
 
-       if (token.type == '}') {
+       if (token.kind == '}') {
                errorf(HERE, "empty enum not allowed");
                next_token();
                return;
        }
 
        add_anchor_token('}');
+       add_anchor_token(',');
        do {
-               if (token.type != T_IDENTIFIER) {
-                       parse_error_expected("while parsing enum entry", T_IDENTIFIER, NULL);
-                       eat_block();
-                       rem_anchor_token('}');
-                       return;
-               }
-
-               entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, token.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.source_position;
-               next_token();
+               rem_anchor_token('=');
 
                if (next_if('=')) {
                        expression_t *value = parse_constant_expression();
@@ -2469,13 +2372,11 @@ static void parse_enum_entries(type_t *const enum_type)
                }
 
                record_entity(entity, false);
-       } while (next_if(',') && token.type != '}');
+       } while (next_if(',') && token.kind != '}');
+       rem_anchor_token(',');
        rem_anchor_token('}');
 
-       expect('}', end_error);
-
-end_error:
-       ;
+       expect('}');
 }
 
 static type_t *parse_enum_specifier(void)
@@ -2485,19 +2386,19 @@ static type_t *parse_enum_specifier(void)
        symbol_t               *symbol;
 
        eat(T_enum);
-       switch (token.type) {
+       switch (token.kind) {
                case T_IDENTIFIER:
-                       symbol = token.symbol;
+                       symbol = token.identifier.symbol;
                        entity = get_tag(symbol, ENTITY_ENUM);
                        next_token();
 
                        if (entity != NULL) {
                                if (entity->base.parent_scope != current_scope &&
-                                               (token.type == '{' || token.type == ';')) {
+                                               (token.kind == '{' || token.kind == ';')) {
                                        /* we're in an inner scope and have a definition. Shadow
                                         * existing definition in outer scope */
                                        entity = NULL;
-                               } else if (entity->enume.complete && token.type == '{') {
+                               } else if (entity->enume.complete && token.kind == '{') {
                                        source_position_t const *const ppos = &entity->base.source_position;
                                        errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                                }
@@ -2516,16 +2417,15 @@ 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);
-       type->enumt.enume  = &entity->enume;
-       type->enumt.akind  = ATOMIC_TYPE_INT;
+       type_t *const type     = allocate_type_zero(TYPE_ENUM);
+       type->enumt.enume      = &entity->enume;
+       type->enumt.base.akind = ATOMIC_TYPE_INT;
 
-       if (token.type == '{') {
+       if (token.kind == '{') {
                if (symbol != NULL) {
                        environment_push(entity);
                }
@@ -2562,22 +2462,14 @@ static type_t *parse_typeof(void)
 
        type_t *type;
 
-       expect('(', end_error);
+       expect('(');
        add_anchor_token(')');
 
        expression_t *expression  = NULL;
 
-       bool old_type_prop     = in_type_prop;
-       bool old_gcc_extension = in_gcc_extension;
-       in_type_prop           = true;
-
-       while (next_if(T___extension__)) {
-               /* This can be a prefix to a typename or an expression. */
-               in_gcc_extension = true;
-       }
-       switch (token.type) {
+       switch (token.kind) {
        case T_IDENTIFIER:
-               if (is_typedef_symbol(token.symbol)) {
+               if (is_typedef_symbol(token.identifier.symbol)) {
        DECLARATION_START
                        type = parse_typename();
                } else {
@@ -2587,19 +2479,15 @@ static type_t *parse_typeof(void)
                }
                break;
        }
-       in_type_prop     = old_type_prop;
-       in_gcc_extension = old_gcc_extension;
 
        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 {
@@ -2638,45 +2526,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.type != 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.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.type != 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.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;
 }
 
@@ -2685,12 +2571,12 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
        attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
        if (next_if(T_restrict)) {
                kind = ATTRIBUTE_MS_RESTRICT;
-       } else if (token.type == T_IDENTIFIER) {
-               const char *name = token.symbol->string;
+       } else if (token.kind == T_IDENTIFIER) {
+               const char *name = token.identifier.symbol->string;
                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;
                        }
@@ -2722,40 +2608,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;
@@ -2770,20 +2649,19 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
 
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
-       type_t            *type              = NULL;
-       type_qualifiers_t  qualifiers        = TYPE_QUALIFIER_NONE;
-       unsigned           type_specifiers   = 0;
-       bool               newtype           = false;
-       bool               saw_error         = false;
-       bool               old_gcc_extension = in_gcc_extension;
+       type_t            *type            = NULL;
+       type_qualifiers_t  qualifiers      = TYPE_QUALIFIER_NONE;
+       unsigned           type_specifiers = 0;
+       bool               newtype         = false;
+       bool               saw_error       = false;
 
        memset(specifiers, 0, sizeof(*specifiers));
-       specifiers->source_position = token.source_position;
+       specifiers->source_position = token.base.source_position;
 
        while (true) {
                specifiers->attributes = parse_attributes(specifiers->attributes);
 
-               switch (token.type) {
+               switch (token.kind) {
                /* storage class */
 #define MATCH_STORAGE_CLASS(token, class)                                  \
                case token:                                                        \
@@ -2847,11 +2725,6 @@ wrong_thread_storage_class:
                MATCH_TYPE_QUALIFIER(T___uptr,   TYPE_QUALIFIER_UPTR);
                MATCH_TYPE_QUALIFIER(T___sptr,   TYPE_QUALIFIER_SPTR);
 
-               case T___extension__:
-                       next_token();
-                       in_gcc_extension = true;
-                       break;
-
                /* type specifiers */
 #define MATCH_SPECIFIER(token, specifier, name)                         \
                case token:                                                     \
@@ -2939,7 +2812,7 @@ wrong_thread_storage_class:
                                /* Be somewhat resilient to typos like 'unsigned lng* f()' in a
                                 * declaration, so it doesn't generate errors about expecting '(' or
                                 * '{' later on. */
-                               switch (look_ahead(1)->type) {
+                               switch (look_ahead(1)->kind) {
                                        STORAGE_CLASSES
                                        TYPE_SPECIFIERS
                                        case T_const:
@@ -2959,12 +2832,12 @@ wrong_thread_storage_class:
                                }
                        }
 
-                       type_t *const typedef_type = get_typedef_type(token.symbol);
+                       type_t *const typedef_type = get_typedef_type(token.identifier.symbol);
                        if (typedef_type == NULL) {
                                /* Be somewhat resilient to typos like 'vodi f()' at the beginning of a
                                 * declaration, so it doesn't generate 'implicit int' followed by more
                                 * errors later on. */
-                               token_type_t const la1_type = (token_type_t)look_ahead(1)->type;
+                               token_kind_t const la1_type = (token_kind_t)look_ahead(1)->kind;
                                switch (la1_type) {
                                        DECLARATION_START
                                        case T_IDENTIFIER:
@@ -2972,8 +2845,9 @@ wrong_thread_storage_class:
                                        case '*': {
                                                errorf(HERE, "%K does not name a type", &token);
 
-                                               entity_t *entity =
-                                                       create_error_entity(token.symbol, ENTITY_TYPEDEF);
+                                               symbol_t *symbol = token.identifier.symbol;
+                                               entity_t *entity
+                                                       = create_error_entity(symbol, ENTITY_TYPEDEF);
 
                                                type = allocate_type_zero(TYPE_TYPEDEF);
                                                type->typedeft.typedefe = &entity->typedefe;
@@ -3002,8 +2876,6 @@ wrong_thread_storage_class:
 finish_specifiers:
        specifiers->attributes = parse_attributes(specifiers->attributes);
 
-       in_gcc_extension = old_gcc_extension;
-
        if (type == NULL || (saw_error && type_specifiers != 0)) {
                atomic_type_kind_t atomic_type;
 
@@ -3166,15 +3038,13 @@ warn_about_long_long:
                }
 
                if (type_specifiers & SPECIFIER_COMPLEX) {
-                       type                = allocate_type_zero(TYPE_COMPLEX);
-                       type->complex.akind = atomic_type;
+                       type = allocate_type_zero(TYPE_COMPLEX);
                } else if (type_specifiers & SPECIFIER_IMAGINARY) {
-                       type                  = allocate_type_zero(TYPE_IMAGINARY);
-                       type->imaginary.akind = atomic_type;
+                       type = allocate_type_zero(TYPE_IMAGINARY);
                } else {
-                       type                 = allocate_type_zero(TYPE_ATOMIC);
-                       type->atomic.akind   = atomic_type;
+                       type = allocate_type_zero(TYPE_ATOMIC);
                }
+               type->atomic.akind = atomic_type;
                newtype = true;
        } else if (type_specifiers != 0) {
                errorf(&specifiers->source_position, "multiple datatypes in declaration");
@@ -3203,7 +3073,7 @@ static type_qualifiers_t parse_type_qualifiers(void)
        type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
 
        while (true) {
-               switch (token.type) {
+               switch (token.kind) {
                /* type qualifiers */
                MATCH_TYPE_QUALIFIER(T_const,    TYPE_QUALIFIER_CONST);
                MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
@@ -3226,15 +3096,15 @@ static type_qualifiers_t parse_type_qualifiers(void)
  */
 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.symbol);
-               entity->base.source_position = token.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();
 
                if (scope != NULL)
                        append_entity(scope, entity);
-       } while (next_if(',') && token.type == T_IDENTIFIER);
+       } while (next_if(',') && token.kind == T_IDENTIFIER);
 }
 
 static entity_t *parse_parameter(void)
@@ -3265,19 +3135,29 @@ static void semantic_parameter_incomplete(const entity_t *entity)
 static bool has_parameters(void)
 {
        /* func(void) is not a parameter */
-       if (token.type == T_IDENTIFIER) {
-               entity_t const *const entity = get_entity(token.symbol, NAMESPACE_NORMAL);
+       if (look_ahead(1)->kind != ')')
+               return true;
+       if (token.kind == T_IDENTIFIER) {
+               entity_t const *const entity
+                       = get_entity(token.identifier.symbol, NAMESPACE_NORMAL);
                if (entity == NULL)
                        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;
-       } else if (token.type != T_void) {
+               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)->type != ')')
-               return true;
        next_token();
        return false;
 }
@@ -3290,33 +3170,27 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
 {
        eat('(');
        add_anchor_token(')');
-       int saved_comma_state = save_and_reset_anchor_state(',');
-
-       if (token.type == T_IDENTIFIER &&
-           !is_typedef_symbol(token.symbol)) {
-               token_type_t la1_type = (token_type_t)look_ahead(1)->type;
-               if (la1_type == ',' || la1_type == ')') {
-                       type->kr_style_parameters = true;
-                       parse_identifier_list(scope);
-                       goto parameters_finished;
-               }
-       }
 
-       if (token.type == ')') {
+       if (token.kind == T_IDENTIFIER                  &&
+           !is_typedef_symbol(token.identifier.symbol) &&
+           (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
+               type->kr_style_parameters = true;
+               parse_identifier_list(scope);
+       } else if (token.kind == ')') {
                /* ISO/IEC 14882:1998(E) Â§C.1.6:1 */
                if (!(c_mode & _CXX))
                        type->unspecified_parameters = true;
        } else if (has_parameters()) {
                function_parameter_t **anchor = &type->parameters;
+               add_anchor_token(',');
                do {
-                       switch (token.type) {
+                       switch (token.kind) {
                        case T_DOTDOTDOT:
                                next_token();
                                type->variadic = true;
                                goto parameters_finished;
 
                        case T_IDENTIFIER:
-                       case T___extension__:
                        DECLARATION_START
                        {
                                entity_t *entity = parse_parameter();
@@ -3345,19 +3219,16 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                                goto parameters_finished;
                        }
                } while (next_if(','));
+parameters_finished:
+               rem_anchor_token(',');
        }
 
-parameters_finished:
        rem_anchor_token(')');
-       expect(')', end_error);
-
-end_error:
-       restore_anchor_state(',', saved_comma_state);
+       expect(')');
 }
 
 typedef enum construct_type_kind_t {
-       CONSTRUCT_INVALID,
-       CONSTRUCT_POINTER,
+       CONSTRUCT_POINTER = 1,
        CONSTRUCT_REFERENCE,
        CONSTRUCT_FUNCTION,
        CONSTRUCT_ARRAY
@@ -3455,10 +3326,10 @@ static construct_type_t *parse_array_declarator(void)
        array->is_static       = is_static;
 
        expression_t *size = NULL;
-       if (token.type == '*' && look_ahead(1)->type == ']') {
+       if (token.kind == '*' && look_ahead(1)->kind == ']') {
                array->is_variable = true;
                next_token();
-       } else if (token.type != ']') {
+       } else if (token.kind != ']') {
                size = parse_assignment_expression();
 
                /* Â§6.7.5.2:1  Array size must have integer type */
@@ -3478,9 +3349,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;
 }
 
@@ -3525,7 +3394,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
        for (;;) {
                construct_type_t *type;
                //variable_t       *based = NULL; /* MS __based extension */
-               switch (token.type) {
+               switch (token.kind) {
                        case '&':
                                type = parse_reference_declarator();
                                break;
@@ -3553,13 +3422,13 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
 ptr_operator_end: ;
        construct_type_t *inner_types = NULL;
 
-       switch (token.type) {
+       switch (token.kind) {
        case T_IDENTIFIER:
                if (env->must_be_abstract) {
                        errorf(HERE, "no identifier expected in typename");
                } else {
-                       env->symbol          = token.symbol;
-                       env->source_position = token.source_position;
+                       env->symbol          = token.identifier.symbol;
+                       env->source_position = token.base.source_position;
                }
                next_token();
                break;
@@ -3567,9 +3436,9 @@ ptr_operator_end: ;
        case '(': {
                /* Parenthesized declarator or function declarator? */
                token_t const *const la1 = look_ahead(1);
-               switch (la1->type) {
+               switch (la1->kind) {
                        case T_IDENTIFIER:
-                               if (is_typedef_symbol(la1->symbol)) {
+                               if (is_typedef_symbol(la1->identifier.symbol)) {
                        case ')':
                                        /* Â§6.7.6:2 footnote 126:  Empty parentheses in a type name are
                                         * interpreted as ``function with no parameter specification'', rather
@@ -3594,7 +3463,7 @@ ptr_operator_end: ;
                                                env->must_be_abstract = true;
                                        }
                                        rem_anchor_token(')');
-                                       expect(')', end_error);
+                                       expect(')');
                                }
                                break;
                }
@@ -3613,7 +3482,7 @@ ptr_operator_end: ;
 
        for (;;) {
                construct_type_t *type;
-               switch (token.type) {
+               switch (token.kind) {
                case '(': {
                        scope_t *scope = NULL;
                        if (!env->must_be_abstract) {
@@ -3643,8 +3512,6 @@ declarator_finished:
        *anchor = inner_types;
 
        return first;
-end_error:
-       return NULL;
 }
 
 static type_t *construct_declarator_type(construct_type_t *construct_list,
@@ -3654,8 +3521,6 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
        for (; iter != NULL; iter = iter->base.next) {
                source_position_t const* const pos = &iter->base.pos;
                switch (iter->kind) {
-               case CONSTRUCT_INVALID:
-                       break;
                case CONSTRUCT_FUNCTION: {
                        construct_function_type_t *function      = &iter->function;
                        type_t                    *function_type = function->function_type;
@@ -3670,7 +3535,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                                errorf(pos, "function returning array is not allowed");
                        } else {
                                if (skipped_return_type->base.qualifiers != 0) {
-                                       warningf(WARN_OTHER, pos, "type qualifiers in return type of function type are meaningless");
+                                       warningf(WARN_IGNORED_QUALIFIERS, pos, "type qualifiers in return type of function type are meaningless");
                                }
                        }
 
@@ -3820,9 +3685,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)) {
@@ -3840,8 +3704,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)) {
@@ -3857,10 +3722,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;
@@ -3878,7 +3743,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;
 
@@ -3906,7 +3771,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;
@@ -3924,6 +3788,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;
 }
 
@@ -4009,14 +3877,6 @@ warn_arg_count:
        }
 }
 
-/**
- * Check if a symbol is the equal to "main".
- */
-static bool is_sym_main(const symbol_t *const sym)
-{
-       return strcmp(sym->string, "main") == 0;
-}
-
 static void error_redefined_as_different_kind(const source_position_t *pos,
                const entity_t *old, entity_kind_t new_kind)
 {
@@ -4076,6 +3936,8 @@ static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
        }
 }
 
+static bool is_main(entity_t*);
+
 /**
  * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
  * for various problems that occur for multiple definitions
@@ -4090,6 +3952,10 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
        if (symbol == NULL)
                return entity;
 
+       assert(!entity->base.parent_scope);
+       assert(current_scope);
+       entity->base.parent_scope = current_scope;
+
        entity_t *const previous_entity = get_entity(symbol, namespc);
        /* pushing the same entity twice will break the stack structure */
        assert(previous_entity != entity);
@@ -4105,7 +3971,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                        warningf(WARN_STRICT_PROTOTYPES, pos, "function declaration '%#N' is not a prototype", entity);
                }
 
-               if (current_scope == file_scope && is_sym_main(symbol)) {
+               if (is_main(entity)) {
                        check_main(entity);
                }
        }
@@ -4140,8 +4006,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;
                        }
 
@@ -4195,7 +4075,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                                                case STORAGE_CLASS_EXTERN:
                                                        if (is_definition) {
-                                                               if (prev_type->function.unspecified_parameters && !is_sym_main(symbol)) {
+                                                               if (prev_type->function.unspecified_parameters && !is_main(entity)) {
                                                                        warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
                                                                }
                                                        } else if (new_storage_class == STORAGE_CLASS_NONE) {
@@ -4221,7 +4101,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) {
@@ -4265,7 +4145,7 @@ error_redeclaration:
        if (entity->kind == ENTITY_FUNCTION) {
                if (is_definition &&
                                entity->declaration.storage_class != STORAGE_CLASS_STATIC &&
-                               !is_sym_main(symbol)) {
+                               !is_main(entity)) {
                        if (is_warn_on(WARN_MISSING_PROTOTYPES)) {
                                warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
                        } else {
@@ -4282,10 +4162,6 @@ warn_missing_declaration:
        }
 
 finish:
-       assert(entity->base.parent_scope == NULL);
-       assert(current_scope != NULL);
-
-       entity->base.parent_scope = current_scope;
        environment_push(entity);
        append_entity(current_scope, entity);
 
@@ -4301,11 +4177,11 @@ static void parser_error_multiple_definition(entity_t *entity,
 
 static bool is_declaration_specifier(const token_t *token)
 {
-       switch (token->type) {
+       switch (token->kind) {
                DECLARATION_START
                        return true;
                case T_IDENTIFIER:
-                       return is_typedef_symbol(token->symbol);
+                       return is_typedef_symbol(token->identifier.symbol);
 
                default:
                        return false;
@@ -4349,10 +4225,8 @@ static void parse_init_declarator_rest(entity_t *entity)
        env.type             = orig_type;
        env.must_be_constant = must_be_constant;
        env.entity           = entity;
-       current_init_decl    = entity;
 
        initializer_t *initializer = parse_initializer(&env);
-       current_init_decl = NULL;
 
        if (entity->kind == ENTITY_VARIABLE) {
                /* Â§6.7.5:22  array initializers for arrays with unknown size
@@ -4429,20 +4303,18 @@ static void parse_declaration_rest(entity_t *ndeclaration,
        add_anchor_token(';');
        add_anchor_token(',');
        while (true) {
-               entity_t *entity = finished_declaration(ndeclaration, token.type == '=');
+               entity_t *entity = finished_declaration(ndeclaration, token.kind == '=');
 
-               if (token.type == '=') {
+               if (token.kind == '=') {
                        parse_init_declarator_rest(entity);
                } else if (entity->kind == ENTITY_VARIABLE) {
                        /* 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);
                        }
                }
 
@@ -4455,12 +4327,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)
@@ -4493,7 +4364,7 @@ static void parse_declaration(parsed_declaration_func finished_declaration,
        parse_declaration_specifiers(&specifiers);
        rem_anchor_token(';');
 
-       if (token.type == ';') {
+       if (token.kind == ';') {
                parse_anonymous_declaration_rest(&specifiers);
        } else {
                entity_t *entity = parse_declarator(&specifiers, flags);
@@ -4528,9 +4399,7 @@ static void parse_kr_declaration_list(entity_t *entity)
 
        add_anchor_token('{');
 
-       /* push function parameters */
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&entity->function.parameters);
+       PUSH_SCOPE(&entity->function.parameters);
 
        entity_t *parameter = entity->function.parameters.entities;
        for ( ; parameter != NULL; parameter = parameter->base.next) {
@@ -4541,9 +4410,8 @@ static void parse_kr_declaration_list(entity_t *entity)
 
        /* parse declaration list */
        for (;;) {
-               switch (token.type) {
+               switch (token.kind) {
                        DECLARATION_START
-                       case T___extension__:
                        /* This covers symbols, which are no type, too, and results in
                         * better error messages.  The typical cases are misspelled type
                         * names and missing includes. */
@@ -4556,10 +4424,7 @@ static void parse_kr_declaration_list(entity_t *entity)
        }
 decl_list_end:
 
-       /* pop function parameters */
-       assert(current_scope == &entity->function.parameters);
-       scope_pop(old_scope);
-       environment_pop_to(top);
+       POP_SCOPE();
 
        /* update function type */
        type_t *new_type = duplicate_type(type);
@@ -4671,10 +4536,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();
@@ -4746,11 +4607,7 @@ static void check_declarations(void)
 {
        if (is_warn_on(WARN_UNUSED_PARAMETER)) {
                const scope_t *scope = &current_function->parameters;
-
-               /* do not issue unused warnings for main */
-               if (!is_sym_main(current_function->base.base.symbol)) {
-                       warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
-               }
+               warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
        }
        if (is_warn_on(WARN_UNUSED_VARIABLE)) {
                walk_statements(current_function->statement, check_unused_variables,
@@ -4774,10 +4631,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;
                        }
 
@@ -4793,8 +4652,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
@@ -4806,7 +4665,7 @@ static bool expression_returns(expression_t const *const expr)
                case EXPR_BUILTIN_CONSTANT_P:
                case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
                case EXPR_OFFSETOF:
-               case EXPR_INVALID:
+               case EXPR_ERROR:
                        return true;
 
                case EXPR_STATEMENT: {
@@ -4847,20 +4706,17 @@ 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) &&
                                expression_returns(expr->binary.right);
-
-               case EXPR_UNKNOWN:
-                       break;
        }
 
        panic("unhandled expression");
@@ -4903,7 +4759,7 @@ static void check_reachable(statement_t *const stmt)
        statement_t *last = stmt;
        statement_t *next;
        switch (stmt->kind) {
-               case STATEMENT_INVALID:
+               case STATEMENT_ERROR:
                case STATEMENT_EMPTY:
                case STATEMENT_ASM:
                        next = stmt->base.next;
@@ -5055,20 +4911,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:
@@ -5165,9 +5022,9 @@ 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)                     &&
-                           !is_sym_main(current_function->base.base.symbol)) {
+                       if (!is_type_void(ret) &&
+                           is_type_valid(ret) &&
+                           !is_main(current_entity)) {
                                source_position_t const *const pos = &stmt->base.source_position;
                                warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
                        }
@@ -5175,7 +5032,7 @@ found_break_parent:
                }
 
                switch (next->kind) {
-                       case STATEMENT_INVALID:
+                       case STATEMENT_ERROR:
                        case STATEMENT_EMPTY:
                        case STATEMENT_DECLARATION:
                        case STATEMENT_EXPRESSION:
@@ -5183,6 +5040,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");
@@ -5366,6 +5224,24 @@ 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 prepare_main_collect2(entity_t*);
+
 static void parse_external_declaration(void)
 {
        /* function-definitions and declarations both start with declaration
@@ -5376,7 +5252,7 @@ static void parse_external_declaration(void)
        rem_anchor_token(';');
 
        /* must be a declaration */
-       if (token.type == ';') {
+       if (token.kind == ';') {
                parse_anonymous_declaration_rest(&specifiers);
                return;
        }
@@ -5395,7 +5271,7 @@ static void parse_external_declaration(void)
        rem_anchor_token(',');
 
        /* must be a declaration */
-       switch (token.type) {
+       switch (token.kind) {
                case ',':
                case ';':
                case '=':
@@ -5407,7 +5283,7 @@ static void parse_external_declaration(void)
        /* must be a function definition */
        parse_kr_declaration_list(ndeclaration);
 
-       if (token.type != '{') {
+       if (token.kind != '{') {
                parse_error_expected("while parsing function definition", '{', NULL);
                eat_until_matching_token(';');
                return;
@@ -5459,12 +5335,8 @@ static void parse_external_declaration(void)
        if (ndeclaration != entity) {
                function->parameters = ndeclaration->function.parameters;
        }
-       assert(is_declaration(entity));
-       type = skip_typeref(entity->declaration.type);
 
-       /* push function parameters and switch scope */
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&function->parameters);
+       PUSH_SCOPE(&function->parameters);
 
        entity_t *parameter = function->parameters.entities;
        for (; parameter != NULL; parameter = parameter->base.next) {
@@ -5488,10 +5360,9 @@ static void parse_external_declaration(void)
                /* parse function body */
                int         label_stack_top      = label_top();
                function_t *old_current_function = current_function;
-               entity_t   *old_current_entity   = current_entity;
                current_function                 = function;
-               current_entity                   = entity;
-               current_parent                   = NULL;
+               PUSH_CURRENT_ENTITY(entity);
+               PUSH_PARENT(NULL);
 
                goto_first   = NULL;
                goto_anchor  = &goto_first;
@@ -5517,64 +5388,36 @@ static void parse_external_declaration(void)
                        }
                }
 
-               assert(current_parent   == NULL);
+               if (is_main(entity)) {
+                       /* Force main to C linkage. */
+                       type_t *const type = entity->declaration.type;
+                       assert(is_type_function(type));
+                       if (type->function.linkage != LINKAGE_C) {
+                               type_t *new_type           = duplicate_type(type);
+                               new_type->function.linkage = LINKAGE_C;
+                               entity->declaration.type   = identify_new_type(new_type);
+                       }
+
+                       if (enable_main_collect2_hack)
+                               prepare_main_collect2(entity);
+               }
+
+               POP_CURRENT_ENTITY();
+               POP_PARENT();
                assert(current_function == function);
-               assert(current_entity   == entity);
-               current_entity   = old_current_entity;
                current_function = old_current_function;
                label_pop_to(label_stack_top);
        }
 
-       assert(current_scope == &function->parameters);
-       scope_pop(old_scope);
-       environment_pop_to(top);
+       POP_SCOPE();
 }
 
-static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
-                                  source_position_t *source_position,
-                                  const symbol_t *symbol)
+static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
 {
-       type_t *type = allocate_type_zero(TYPE_BITFIELD);
-
-       type->bitfield.base_type       = base_type;
-       type->bitfield.size_expression = size;
-
-       il_size_t bit_size;
-       type_t *skipped_type = skip_typeref(base_type);
-       if (!is_type_integer(skipped_type)) {
-               errorf(source_position, "bitfield base type '%T' is not an integer type", base_type);
-               bit_size = 0;
-       } else {
-               bit_size = get_type_size(base_type) * 8;
-       }
-
-       if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
-               long v = fold_constant_to_int(size);
-               const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
-
-               if (v < 0) {
-                       errorf(source_position, "negative width in bit-field '%Y'",
-                              user_symbol);
-               } else if (v == 0 && symbol != NULL) {
-                       errorf(source_position, "zero width for bit-field '%Y'",
-                              user_symbol);
-               } else if (bit_size > 0 && (il_size_t)v > bit_size) {
-                       errorf(source_position, "width of '%Y' exceeds its type",
-                              user_symbol);
-               } else {
-                       type->bitfield.bit_size = v;
-               }
-       }
-
-       return type;
-}
-
-static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
-{
-       entity_t *iter = compound->members.entities;
-       for (; iter != NULL; iter = iter->base.next) {
-               if (iter->kind != ENTITY_COMPOUND_MEMBER)
-                       continue;
+       entity_t *iter = compound->members.entities;
+       for (; iter != NULL; iter = iter->base.next) {
+               if (iter->kind != ENTITY_COMPOUND_MEMBER)
+                       continue;
 
                if (iter->base.symbol == symbol) {
                        return iter;
@@ -5627,12 +5470,19 @@ static expression_t *create_select(const source_position_t *pos,
        type_t *entry_type = entry->declaration.type;
        type_t *res_type   = get_qualified_type(entry_type, qualifiers);
 
+       /* bitfields need special treatment */
+       if (entry->compound_member.bitfield) {
+               unsigned bit_size = entry->compound_member.bit_size;
+               /* if fewer bits than an int, convert to int (see Â§6.3.1.1) */
+               if (bit_size < get_atomic_type_size(ATOMIC_TYPE_INT) * BITS_PER_BYTE) {
+                       res_type = type_int;
+               }
+       }
+
        /* we always do the auto-type conversions; the & and sizeof parser contains
         * code to revert this! */
        select->base.type = automatic_type_conversion(res_type);
-       if (res_type->kind == TYPE_BITFIELD) {
-               select->base.type = res_type->bitfield.base_type;
-       }
+
 
        return select;
 }
@@ -5666,7 +5516,7 @@ static expression_t *find_create_select(const source_position_t *pos,
 
                        expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
                        sub_addr->base.source_position = *pos;
-                       sub_addr->select.implicit      = true;
+                       sub_addr->base.implicit        = true;
                        return find_create_select(pos, sub_addr, qualifiers, sub_compound,
                                                  symbol);
                }
@@ -5679,38 +5529,77 @@ static expression_t *find_create_select(const source_position_t *pos,
        return NULL;
 }
 
+static void parse_bitfield_member(entity_t *entity)
+{
+       eat(':');
+
+       expression_t *size = parse_constant_expression();
+       long          size_long;
+
+       assert(entity->kind == ENTITY_COMPOUND_MEMBER);
+       type_t *type = entity->declaration.type;
+       if (!is_type_integer(skip_typeref(type))) {
+               errorf(HERE, "bitfield base type '%T' is not an integer type",
+                          type);
+       }
+
+       if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) {
+               /* error already reported by parse_constant_expression */
+               size_long = get_type_size(type) * 8;
+       } else {
+               size_long = fold_constant_to_int(size);
+
+               const symbol_t *symbol = entity->base.symbol;
+               const symbol_t *user_symbol
+                       = symbol == NULL ? sym_anonymous : symbol;
+               unsigned bit_size = get_type_size(type) * 8;
+               if (size_long < 0) {
+                       errorf(HERE, "negative width in bit-field '%Y'", user_symbol);
+               } else if (size_long == 0 && symbol != NULL) {
+                       errorf(HERE, "zero width for bit-field '%Y'", user_symbol);
+               } else if (bit_size > 0 && (unsigned)size_long > bit_size) {
+                       errorf(HERE, "width of bitfield '%Y' exceeds its type",
+                                  user_symbol);
+               } else {
+                       /* hope that people don't invent crazy types with more bits
+                        * than our struct can hold */
+                       assert(size_long <
+                                  (1 << sizeof(entity->compound_member.bit_size)*8));
+               }
+       }
+
+       entity->compound_member.bitfield = true;
+       entity->compound_member.bit_size = (unsigned char)size_long;
+}
+
 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.type == ':') {
-                       source_position_t source_position = *HERE;
-                       next_token();
-
-                       type_t *base_type = specifiers->type;
-                       expression_t *size = parse_constant_expression();
+               if (token.kind == ':') {
+                       /* anonymous bitfield */
+                       type_t *type = specifiers->type;
+                       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;
 
-                       type_t *type = make_bitfield_type(base_type, size,
-                                       &source_position, NULL);
+                       parse_bitfield_member(entity);
 
                        attribute_t  *attributes = parse_attributes(NULL);
                        attribute_t **anchor     = &attributes;
                        while (*anchor != NULL)
                                anchor = &(*anchor)->next;
                        *anchor = specifiers->attributes;
-
-                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL);
-                       entity->base.source_position               = source_position;
-                       entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
-                       entity->declaration.storage_class          = STORAGE_CLASS_NONE;
-                       entity->declaration.type                   = type;
-                       entity->declaration.attributes             = attributes;
-
                        if (attributes != NULL) {
                                handle_entity_attributes(attributes, entity);
                        }
+                       entity->declaration.attributes = attributes;
+
                        append_entity(&compound->members, entity);
                } else {
                        entity = parse_declarator(specifiers,
@@ -5731,17 +5620,10 @@ static void parse_compound_declarators(compound_t *compound,
                                        }
                                }
 
-                               if (token.type == ':') {
-                                       source_position_t source_position = *HERE;
-                                       next_token();
-                                       expression_t *size = parse_constant_expression();
-
-                                       type_t *type          = entity->declaration.type;
-                                       type_t *bitfield_type = make_bitfield_type(type, size,
-                                                       &source_position, entity->base.symbol);
+                               if (token.kind == ':') {
+                                       parse_bitfield_member(entity);
 
                                        attribute_t *attributes = parse_attributes(NULL);
-                                       entity->declaration.type = bitfield_type;
                                        handle_entity_attributes(attributes, entity);
                                } else {
                                        type_t *orig_type = entity->declaration.type;
@@ -5751,9 +5633,11 @@ static void parse_compound_declarators(compound_t *compound,
                                        } else if (is_type_incomplete(type)) {
                                                /* Â§6.7.2.1:16 flexible array member */
                                                if (!is_type_array(type)       ||
-                                                               token.type          != ';' ||
-                                                               look_ahead(1)->type != '}') {
+                                                               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");
                                                }
                                        }
                                }
@@ -5762,9 +5646,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;
 }
 
@@ -5774,19 +5659,21 @@ static void parse_compound_type_entries(compound_t *compound)
        add_anchor_token('}');
 
        for (;;) {
-               switch (token.type) {
+               switch (token.kind) {
                        DECLARATION_START
+                       case T___extension__:
                        case T_IDENTIFIER: {
+                               PUSH_EXTENSION();
                                declaration_specifiers_t specifiers;
                                parse_declaration_specifiers(&specifiers);
                                parse_compound_declarators(compound, &specifiers);
+                               POP_EXTENSION();
                                break;
                        }
 
                        default:
                                rem_anchor_token('}');
-                               expect('}', end_error);
-end_error:
+                               expect('}');
                                /* Â§6.7.2.1:7 */
                                compound->complete = true;
                                return;
@@ -5826,20 +5713,6 @@ struct expression_parser_function_t {
 
 static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
-/**
- * Prints an error message if an expression was expected but not read
- */
-static expression_t *expected_expression_error(void)
-{
-       /* skip the error message if the error token was read */
-       if (token.type != T_ERROR) {
-               errorf(HERE, "expected expression, got token %K", &token);
-       }
-       next_token();
-
-       return create_invalid_expression();
-}
-
 static type_t *get_string_type(void)
 {
        return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr;
@@ -5855,17 +5728,17 @@ static type_t *get_wide_string_type(void)
  */
 static expression_t *parse_string_literal(void)
 {
-       source_position_t begin   = token.source_position;
-       string_t          res     = token.literal;
-       bool              is_wide = (token.type == T_WIDE_STRING_LITERAL);
+       source_position_t begin   = token.base.source_position;
+       string_t          res     = token.string.string;
+       bool              is_wide = (token.kind == T_WIDE_STRING_LITERAL);
 
        next_token();
-       while (token.type == T_STRING_LITERAL
-                       || token.type == T_WIDE_STRING_LITERAL) {
-               warn_string_concat(&token.source_position);
-               res = concat_strings(&res, &token.literal);
+       while (token.kind == T_STRING_LITERAL
+                       || token.kind == T_WIDE_STRING_LITERAL) {
+               warn_string_concat(&token.base.source_position);
+               res = concat_strings(&res, &token.string.string);
                next_token();
-               is_wide |= token.type == T_WIDE_STRING_LITERAL;
+               is_wide |= token.kind == T_WIDE_STRING_LITERAL;
        }
 
        expression_t *literal;
@@ -5898,17 +5771,18 @@ static expression_t *parse_boolean_literal(bool value)
 
 static void warn_traditional_suffix(void)
 {
-       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%Y' suffix", token.symbol);
+       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix",
+                &token.number.suffix);
 }
 
 static void check_integer_suffix(void)
 {
-       symbol_t *suffix = token.symbol;
-       if (suffix == NULL)
+       const string_t *suffix = &token.number.suffix;
+       if (suffix->size == 0)
                return;
 
        bool not_traditional = false;
-       const char *c = suffix->string;
+       const char *c = suffix->begin;
        if (*c == 'l' || *c == 'L') {
                ++c;
                if (*c == *(c-1)) {
@@ -5932,8 +5806,8 @@ static void check_integer_suffix(void)
                }
        }
        if (*c != '\0') {
-               errorf(&token.source_position,
-                      "invalid suffix '%s' on integer constant", suffix->string);
+               errorf(&token.base.source_position,
+                      "invalid suffix '%S' on integer constant", suffix);
        } else if (not_traditional) {
                warn_traditional_suffix();
        }
@@ -5941,13 +5815,13 @@ static void check_integer_suffix(void)
 
 static type_t *check_floatingpoint_suffix(void)
 {
-       symbol_t *suffix = token.symbol;
-       type_t   *type   = type_double;
-       if (suffix == NULL)
+       const string_t *suffix = &token.number.suffix;
+       type_t         *type   = type_double;
+       if (suffix->size == 0)
                return type;
 
        bool not_traditional = false;
-       const char *c = suffix->string;
+       const char *c = suffix->begin;
        if (*c == 'f' || *c == 'F') {
                ++c;
                type = type_float;
@@ -5956,8 +5830,8 @@ static type_t *check_floatingpoint_suffix(void)
                type = type_long_double;
        }
        if (*c != '\0') {
-               errorf(&token.source_position,
-                      "invalid suffix '%s' on floatingpoint constant", suffix->string);
+               errorf(&token.base.source_position,
+                      "invalid suffix '%S' on floatingpoint constant", suffix);
        } else if (not_traditional) {
                warn_traditional_suffix();
        }
@@ -5973,38 +5847,26 @@ static expression_t *parse_number_literal(void)
        expression_kind_t  kind;
        type_t            *type;
 
-       switch (token.type) {
+       switch (token.kind) {
        case T_INTEGER:
                kind = EXPR_LITERAL_INTEGER;
                check_integer_suffix();
                type = type_int;
                break;
-       case T_INTEGER_OCTAL:
-               kind = EXPR_LITERAL_INTEGER_OCTAL;
-               check_integer_suffix();
-               type = type_int;
-               break;
-       case T_INTEGER_HEXADECIMAL:
-               kind = EXPR_LITERAL_INTEGER_HEXADECIMAL;
-               check_integer_suffix();
-               type = type_int;
-               break;
+
        case T_FLOATINGPOINT:
                kind = EXPR_LITERAL_FLOATINGPOINT;
                type = check_floatingpoint_suffix();
                break;
-       case T_FLOATINGPOINT_HEXADECIMAL:
-               kind = EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL;
-               type = check_floatingpoint_suffix();
-               break;
+
        default:
                panic("unexpected token type in parse_number_literal");
        }
 
        expression_t *literal = allocate_expression_zero(kind);
        literal->base.type      = type;
-       literal->literal.value  = token.literal;
-       literal->literal.suffix = token.symbol;
+       literal->literal.value  = token.number.number;
+       literal->literal.suffix = token.number.suffix;
        next_token();
 
        /* integer type depends on the size of the number and the size
@@ -6022,7 +5884,7 @@ static expression_t *parse_character_constant(void)
 {
        expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
        literal->base.type     = c_mode & _CXX ? type_char : type_int;
-       literal->literal.value = token.literal;
+       literal->literal.value = token.string.string;
 
        size_t len = literal->literal.value.size;
        if (len > 1) {
@@ -6045,7 +5907,7 @@ static expression_t *parse_wide_character_constant(void)
 {
        expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
        literal->base.type     = type_int;
-       literal->literal.value = token.literal;
+       literal->literal.value = token.string.string;
 
        size_t len = wstrlen(&literal->literal.value);
        if (len > 1) {
@@ -6056,8 +5918,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;
@@ -6065,12 +5926,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);
@@ -6123,8 +5983,7 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
                entity_t *entity = expression->select.compound_entry;
                assert(is_declaration(entity));
                type_t   *type   = entity->declaration.type;
-               return get_qualified_type(type,
-                               expression->base.type->base.qualifiers);
+               return get_qualified_type(type, expression->base.type->base.qualifiers);
        }
 
        case EXPR_UNARY_DEREFERENCE: {
@@ -6197,13 +6056,9 @@ static entity_t *parse_qualified_identifier(void)
 
        entity_t *entity;
        while (true) {
-               if (token.type != 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.symbol;
-               pos    = *HERE;
-               next_token();
 
                /* lookup entity */
                entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
@@ -6232,9 +6087,10 @@ static entity_t *parse_qualified_identifier(void)
        }
 
        if (entity == NULL) {
-               if (!strict_mode && token.type == '(') {
+               if (!strict_mode && token.kind == '(') {
                        /* an implicitly declared function */
-                       warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of function '%Y'", symbol);
+                       warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos,
+                                "implicit declaration of function '%Y'", symbol);
                        entity = create_implicit_function(symbol, &pos);
                } else {
                        errorf(&pos, "unknown identifier '%Y' found.", symbol);
@@ -6247,7 +6103,7 @@ static entity_t *parse_qualified_identifier(void)
 
 static expression_t *parse_reference(void)
 {
-       source_position_t const pos    = token.source_position;
+       source_position_t const pos    = token.base.source_position;
        entity_t         *const entity = parse_qualified_identifier();
 
        type_t *orig_type;
@@ -6265,7 +6121,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;
@@ -6292,11 +6148,6 @@ static expression_t *parse_reference(void)
 
        check_deprecated(&pos, entity);
 
-       if (entity == current_init_decl && !in_type_prop && entity->kind == ENTITY_VARIABLE) {
-               current_init_decl = NULL;
-               warningf(WARN_INIT_SELF, &pos, "variable '%#N' is initialized by itself", entity);
-       }
-
        return expression;
 }
 
@@ -6310,7 +6161,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 */
@@ -6376,9 +6227,9 @@ static expression_t *parse_cast(void)
        type_t *type = parse_typename();
 
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
-       if (token.type == '{') {
+       if (token.kind == '{') {
                return parse_compound_literal(&pos, type);
        }
 
@@ -6394,8 +6245,6 @@ static expression_t *parse_cast(void)
        }
 
        return cast;
-end_error:
-       return create_invalid_expression();
 }
 
 /**
@@ -6429,9 +6278,7 @@ static expression_t *parse_statement_expression(void)
        expression->base.type = type;
 
        rem_anchor_token(')');
-       expect(')', end_error);
-
-end_error:
+       expect(')');
        return expression;
 }
 
@@ -6441,13 +6288,13 @@ end_error:
 static expression_t *parse_parenthesized_expression(void)
 {
        token_t const* const la1 = look_ahead(1);
-       switch (la1->type) {
+       switch (la1->kind) {
        case '{':
                /* gcc extension: a statement expression */
                return parse_statement_expression();
 
        case T_IDENTIFIER:
-               if (is_typedef_symbol(la1->symbol)) {
+               if (is_typedef_symbol(la1->identifier.symbol)) {
        DECLARATION_START
                        return parse_cast();
                }
@@ -6458,9 +6305,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;
 }
 
@@ -6528,29 +6374,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.type != 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.symbol;
-       next_token();
 
        designator_t *last_designator = result;
        while (true) {
                if (next_if('.')) {
-                       if (token.type != 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.symbol;
-                       next_token();
 
                        last_designator->next = designator;
                        last_designator       = designator;
@@ -6562,7 +6397,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;
                        }
@@ -6575,8 +6410,6 @@ static designator_t *parse_designator(void)
        }
 
        return result;
-end_error:
-       return NULL;
 }
 
 /**
@@ -6589,15 +6422,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;
@@ -6610,14 +6443,12 @@ static expression_t *parse_offsetof(void)
        descend_into_subtype(&path);
 
        if (!walk_designator(&path, designator, true)) {
-               return create_invalid_expression();
+               return create_error_expression();
        }
 
        DEL_ARR_F(path.path);
 
        return expression;
-end_error:
-       return create_invalid_expression();
 }
 
 /**
@@ -6629,11 +6460,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;
@@ -6648,12 +6480,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_invalid_expression();
+       rem_anchor_token(')');
+       expect(')');
+       return expression;
 }
 
 /**
@@ -6665,19 +6497,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_invalid_expression();
 }
 
 /**
@@ -6689,24 +6523,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_invalid_expression();
 }
 
 /**
@@ -6718,16 +6554,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_invalid_expression();
 }
 
 /**
@@ -6739,20 +6573,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_invalid_expression();
 }
 
 /**
@@ -6762,7 +6594,7 @@ static expression_t *parse_compare_builtin(void)
 {
        expression_t *expression;
 
-       switch (token.type) {
+       switch (token.kind) {
        case T___builtin_isgreater:
                expression = allocate_expression_zero(EXPR_BINARY_ISGREATER);
                break;
@@ -6787,11 +6619,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;
@@ -6808,8 +6644,6 @@ static expression_t *parse_compare_builtin(void)
        }
 
        return expression;
-end_error:
-       return create_invalid_expression();
 }
 
 /**
@@ -6821,16 +6655,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_invalid_expression();
 }
 
 /**
@@ -6838,10 +6670,10 @@ end_error:
  */
 static label_t *get_label(void)
 {
-       assert(token.type == T_IDENTIFIER);
+       assert(token.kind == T_IDENTIFIER);
        assert(current_function != NULL);
 
-       entity_t *label = get_entity(token.symbol, NAMESPACE_LABEL);
+       entity_t *label = get_entity(token.identifier.symbol, NAMESPACE_LABEL);
        /* If we find a local label, we already created the declaration. */
        if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
                if (label->base.parent_scope != current_scope) {
@@ -6850,7 +6682,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.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);
        }
 
@@ -6863,11 +6696,11 @@ static label_t *get_label(void)
  */
 static expression_t *parse_label_address(void)
 {
-       source_position_t source_position = token.source_position;
+       source_position_t source_position = token.base.source_position;
        eat(T_ANDAND);
-       if (token.type != T_IDENTIFIER) {
+       if (token.kind != T_IDENTIFIER) {
                parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
-               return create_invalid_expression();
+               return create_error_expression();
        }
 
        label_t *const label = get_label();
@@ -6896,21 +6729,21 @@ static expression_t *parse_noop_expression(void)
 
        eat(T___noop);
 
-       if (token.type == '(') {
+       if (token.kind == '(') {
                /* parse arguments */
                eat('(');
                add_anchor_token(')');
                add_anchor_token(',');
 
-               if (token.type != ')') do {
+               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;
 }
 
@@ -6919,14 +6752,11 @@ end_error:
  */
 static expression_t *parse_primary_expression(void)
 {
-       switch (token.type) {
+       switch (token.kind) {
        case T_false:                        return parse_boolean_literal(false);
        case T_true:                         return parse_boolean_literal(true);
        case T_INTEGER:
-       case T_INTEGER_OCTAL:
-       case T_INTEGER_HEXADECIMAL:
-       case T_FLOATINGPOINT:
-       case T_FLOATINGPOINT_HEXADECIMAL:    return parse_number_literal();
+       case T_FLOATINGPOINT:                return parse_number_literal();
        case T_CHARACTER_CONSTANT:           return parse_character_constant();
        case T_WIDE_CHARACTER_CONSTANT:      return parse_wide_character_constant();
        case T_STRING_LITERAL:
@@ -6961,7 +6791,7 @@ static expression_t *parse_primary_expression(void)
        case T_COLONCOLON:
                return parse_reference();
        case T_IDENTIFIER:
-               if (!is_typedef_symbol(token.symbol)) {
+               if (!is_typedef_symbol(token.identifier.symbol)) {
                        return parse_reference();
                }
                /* FALLTHROUGH */
@@ -6971,13 +6801,13 @@ static expression_t *parse_primary_expression(void)
                parse_declaration_specifiers(&specifiers);
                type_t const *const type = parse_abstract_declarator(specifiers.type);
                errorf(&pos, "encountered type '%T' while parsing expression", type);
-               return create_invalid_expression();
+               return create_error_expression();
        }
        }
 
        errorf(HERE, "unexpected token %K, expected an expression", &token);
        eat_until_anchor();
-       return create_invalid_expression();
+       return create_error_expression();
 }
 
 static expression_t *parse_array_expression(expression_t *left)
@@ -7034,11 +6864,16 @@ check_idx:
        arr->base.type = res_type;
 
        rem_anchor_token(']');
-       expect(']', end_error);
-end_error:
+       expect(']');
        return expr;
 }
 
+static bool is_bitfield(const expression_t *expression)
+{
+       return expression->kind == EXPR_SELECT
+               && expression->select.compound_entry->compound_member.bitfield;
+}
+
 static expression_t *parse_typeprop(expression_kind_t const kind)
 {
        expression_t  *tp_expression = allocate_expression_zero(kind);
@@ -7046,21 +6881,17 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
 
        eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
 
-       /* we only refer to a type property, mark this case */
-       bool old     = in_type_prop;
-       in_type_prop = true;
-
        type_t       *orig_type;
        expression_t *expression;
-       if (token.type == '(' && is_declaration_specifier(look_ahead(1))) {
+       if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) {
                source_position_t const pos = *HERE;
                next_token();
                add_anchor_token(')');
                orig_type = parse_typename();
                rem_anchor_token(')');
-               expect(')', end_error);
+               expect(')');
 
-               if (token.type == '{') {
+               if (token.kind == '{') {
                        /* It was not sizeof(type) after all.  It is sizeof of an expression
                         * starting with a compound literal */
                        expression = parse_compound_literal(&pos, orig_type);
@@ -7070,6 +6901,12 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
                expression = parse_subexpression(PREC_UNARY);
 
 typeprop_expression:
+               if (is_bitfield(expression)) {
+                       char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+                       errorf(&tp_expression->base.source_position,
+                                  "operand of %s expression must not be a bitfield", what);
+               }
+
                tp_expression->typeprop.tp_expression = expression;
 
                orig_type = revert_automatic_type_conversion(expression);
@@ -7080,7 +6917,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) {
@@ -7091,12 +6928,7 @@ typeprop_expression:
                } else {
                        wrong_type = "function";
                }
-       } else {
-               if (is_type_incomplete(type))
-                       wrong_type = "incomplete";
        }
-       if (type->kind == TYPE_BITFIELD)
-               wrong_type = "bitfield";
 
        if (wrong_type != NULL) {
                char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
@@ -7105,8 +6937,6 @@ typeprop_expression:
                                what, wrong_type, orig_type);
        }
 
-end_error:
-       in_type_prop = old;
        return tp_expression;
 }
 
@@ -7122,17 +6952,14 @@ static expression_t *parse_alignof(void)
 
 static expression_t *parse_select_expression(expression_t *addr)
 {
-       assert(token.type == '.' || token.type == T_MINUSGREATER);
-       bool select_left_arrow = (token.type == T_MINUSGREATER);
+       assert(token.kind == '.' || token.kind == T_MINUSGREATER);
+       bool select_left_arrow = (token.kind == T_MINUSGREATER);
        source_position_t const pos = *HERE;
        next_token();
 
-       if (token.type != T_IDENTIFIER) {
-               parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
-               return create_invalid_expression();
-       }
-       symbol_t *symbol = token.symbol;
-       next_token();
+       symbol_t *const symbol = expect_identifier("while parsing select", NULL);
+       if (!symbol)
+               return create_error_expression();
 
        type_t *const orig_type = addr->base.type;
        type_t *const type      = skip_typeref(orig_type);
@@ -7163,14 +6990,14 @@ static expression_t *parse_select_expression(expression_t *addr)
                               "request for member '%Y' in something not a struct or union, but '%T'",
                               symbol, type_left);
                }
-               return create_invalid_expression();
+               return create_error_expression();
        }
 
        compound_t *compound = type_left->compound.compound;
        if (!compound->complete) {
                errorf(&pos, "request for member '%Y' in incomplete type '%T'",
                       symbol, type_left);
-               return create_invalid_expression();
+               return create_error_expression();
        }
 
        type_qualifiers_t  qualifiers = type_left->base.qualifiers;
@@ -7179,7 +7006,7 @@ static expression_t *parse_select_expression(expression_t *addr)
 
        if (result == NULL) {
                errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol);
-               return create_invalid_expression();
+               return create_error_expression();
        }
 
        return result;
@@ -7243,32 +7070,25 @@ static void check_call_argument(type_t          *expected_type,
 /**
  * Handle the semantic restrictions of builtin calls
  */
-static void handle_builtin_argument_restrictions(call_expression_t *call) {
-       switch (call->function->reference.entity->function.btk) {
-               case bk_gnu_builtin_return_address:
-               case bk_gnu_builtin_frame_address: {
+static void handle_builtin_argument_restrictions(call_expression_t *call)
+{
+       entity_t *entity = call->function->reference.entity;
+       switch (entity->function.btk) {
+       case BUILTIN_FIRM:
+               switch (entity->function.b.firm_builtin_kind) {
+               case ir_bk_return_address:
+               case ir_bk_frame_address: {
                        /* argument must be constant */
                        call_argument_t *argument = call->arguments;
 
                        if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
                                errorf(&call->base.source_position,
-                                      "argument of '%Y' must be a constant expression",
-                                      call->function->reference.entity->base.symbol);
-                       }
-                       break;
-               }
-               case bk_gnu_builtin_object_size:
-                       if (call->arguments == NULL)
-                               break;
-
-                       call_argument_t *arg = call->arguments->next;
-                       if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
-                               errorf(&call->base.source_position,
-                                          "second argument of '%Y' must be a constant expression",
+                                          "argument of '%Y' must be a constant expression",
                                           call->function->reference.entity->base.symbol);
                        }
                        break;
-               case bk_gnu_builtin_prefetch:
+               }
+               case ir_bk_prefetch:
                        /* second and third argument must be constant if existent */
                        if (call->arguments == NULL)
                                break;
@@ -7278,22 +7098,37 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                        if (rw != NULL) {
                                if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
                                        errorf(&call->base.source_position,
-                                              "second argument of '%Y' must be a constant expression",
-                                              call->function->reference.entity->base.symbol);
+                                                  "second argument of '%Y' must be a constant expression",
+                                                  call->function->reference.entity->base.symbol);
                                }
                                locality = rw->next;
                        }
                        if (locality != NULL) {
                                if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
                                        errorf(&call->base.source_position,
-                                              "third argument of '%Y' must be a constant expression",
-                                              call->function->reference.entity->base.symbol);
+                                                  "third argument of '%Y' must be a constant expression",
+                                                  call->function->reference.entity->base.symbol);
                                }
                                locality = rw->next;
                        }
                        break;
                default:
                        break;
+               }
+
+       case BUILTIN_OBJECT_SIZE:
+               if (call->arguments == NULL)
+                       break;
+
+               call_argument_t *arg = call->arguments->next;
+               if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
+                       errorf(&call->base.source_position,
+                                  "second argument of '%Y' must be a constant expression",
+                                  call->function->reference.entity->base.symbol);
+               }
+               break;
+       default:
+               break;
        }
 }
 
@@ -7332,7 +7167,7 @@ static expression_t *parse_call_expression(expression_t *expression)
        add_anchor_token(')');
        add_anchor_token(',');
 
-       if (token.type != ')') {
+       if (token.kind != ')') {
                call_argument_t **anchor = &call->arguments;
                do {
                        call_argument_t *argument = allocate_ast_zero(sizeof(*argument));
@@ -7344,7 +7179,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;
@@ -7389,11 +7224,10 @@ static expression_t *parse_call_expression(expression_t *expression)
        if (expression->kind == EXPR_REFERENCE) {
                reference_expression_t *reference = &expression->reference;
                if (reference->entity->kind == ENTITY_FUNCTION &&
-                   reference->entity->function.btk != bk_none)
+                   reference->entity->function.btk != BUILTIN_NONE)
                        handle_builtin_argument_restrictions(call);
        }
 
-end_error:
        return result;
 }
 
@@ -7489,14 +7323,13 @@ static expression_t *parse_conditional_expression(expression_t *expression)
 
        expression_t *true_expression = expression;
        bool          gnu_cond = false;
-       if (GNU_MODE && token.type == ':') {
+       if (GNU_MODE && token.kind == ':') {
                gnu_cond = true;
        } else {
                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);
 
@@ -7508,16 +7341,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;
@@ -7550,8 +7381,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))) {
@@ -7591,12 +7421,9 @@ types_incompatible:
  */
 static expression_t *parse_extension(void)
 {
-       eat(T___extension__);
-
-       bool old_gcc_extension   = in_gcc_extension;
-       in_gcc_extension         = true;
+       PUSH_EXTENSION();
        expression_t *expression = parse_subexpression(PREC_UNARY);
-       in_gcc_extension         = old_gcc_extension;
+       POP_EXTENSION();
        return expression;
 }
 
@@ -7610,16 +7437,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_invalid_expression();
 }
 
 /**
@@ -7635,8 +7460,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);
@@ -7648,7 +7472,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");
        }
@@ -7668,7 +7492,7 @@ static expression_t *parse_throw(void)
        eat(T_throw);
 
        expression_t *value = NULL;
-       switch (token.type) {
+       switch (token.kind) {
                EXPRESSION_START {
                        value = parse_assignment_expression();
                        /* ISO/IEC 14882:1998(E) Â§15.1:3 */
@@ -7679,8 +7503,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);
                                }
@@ -7703,7 +7526,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);
@@ -7770,6 +7593,13 @@ static void semantic_incdec(unary_expression_t *expression)
        expression->base.type = orig_type;
 }
 
+static void promote_unary_int_expr(unary_expression_t *const expr, type_t *const type)
+{
+       type_t *const res_type = promote_integer(type);
+       expr->base.type = res_type;
+       expr->value     = create_implicit_cast(expr->value, res_type);
+}
+
 static void semantic_unexpr_arithmetic(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
@@ -7781,9 +7611,11 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
                                "operation needs an arithmetic type");
                }
                return;
+       } else if (is_type_integer(type)) {
+               promote_unary_int_expr(expression, type);
+       } else {
+               expression->base.type = orig_type;
        }
-
-       expression->base.type = orig_type;
 }
 
 static void semantic_unexpr_plus(unary_expression_t *expression)
@@ -7812,7 +7644,7 @@ static void semantic_unexpr_integer(unary_expression_t *expression)
                return;
        }
 
-       expression->base.type = orig_type;
+       promote_unary_int_expr(expression, type);
 }
 
 static void semantic_dereference(unary_expression_t *expression)
@@ -7879,10 +7711,9 @@ static void semantic_take_addr(unary_expression_t *expression)
        if (!is_lvalue(value)) {
                errorf(&expression->base.source_position, "'&' requires an lvalue");
        }
-       if (type->kind == TYPE_BITFIELD) {
+       if (is_bitfield(value)) {
                errorf(&expression->base.source_position,
-                      "'&' not allowed on object with bitfield type '%T'",
-                      type);
+                      "'&' not allowed on bitfield");
        }
 
        set_address_taken(value, false);
@@ -7890,12 +7721,12 @@ static void semantic_take_addr(unary_expression_t *expression)
        expression->base.type = make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
 }
 
-#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \
+#define CREATE_UNARY_EXPRESSION_PARSER(token_kind, unexpression_type, sfunc) \
 static expression_t *parse_##unexpression_type(void)                         \
 {                                                                            \
        expression_t *unary_expression                                           \
                = allocate_expression_zero(unexpression_type);                       \
-       eat(token_type);                                                         \
+       eat(token_kind);                                                         \
        unary_expression->unary.value = parse_subexpression(PREC_UNARY);         \
                                                                                 \
        sfunc(&unary_expression->unary);                                         \
@@ -7920,13 +7751,13 @@ CREATE_UNARY_EXPRESSION_PARSER(T_PLUSPLUS,   EXPR_UNARY_PREFIX_INCREMENT,
 CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT,
                                semantic_incdec)
 
-#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \
+#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_kind, unexpression_type, \
                                                sfunc)                         \
 static expression_t *parse_##unexpression_type(expression_t *left)            \
 {                                                                             \
        expression_t *unary_expression                                            \
                = allocate_expression_zero(unexpression_type);                        \
-       eat(token_type);                                                          \
+       eat(token_kind);                                                          \
        unary_expression->unary.value = left;                                     \
                                                                                  \
        sfunc(&unary_expression->unary);                                          \
@@ -7963,45 +7794,44 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
        if (type_left == type_right)
                return type_left;
 
-       bool const signed_left  = is_type_signed(type_left);
-       bool const signed_right = is_type_signed(type_right);
-       int const  rank_left    = get_rank(type_left);
-       int const  rank_right   = get_rank(type_right);
+       bool     const signed_left  = is_type_signed(type_left);
+       bool     const signed_right = is_type_signed(type_right);
+       unsigned const rank_left    = get_akind_rank(get_akind(type_left));
+       unsigned const rank_right   = get_akind_rank(get_akind(type_right));
 
        if (signed_left == signed_right)
                return rank_left >= rank_right ? type_left : type_right;
 
-       int     s_rank;
-       int     u_rank;
+       unsigned           s_rank;
+       unsigned           u_rank;
+       atomic_type_kind_t s_akind;
+       atomic_type_kind_t u_akind;
        type_t *s_type;
        type_t *u_type;
        if (signed_left) {
-               s_rank = rank_left;
                s_type = type_left;
-               u_rank = rank_right;
                u_type = type_right;
        } else {
-               s_rank = rank_right;
                s_type = type_right;
-               u_rank = rank_left;
                u_type = type_left;
        }
+       s_akind = get_akind(s_type);
+       u_akind = get_akind(u_type);
+       s_rank  = get_akind_rank(s_akind);
+       u_rank  = get_akind_rank(u_akind);
 
        if (u_rank >= s_rank)
                return u_type;
 
-       /* casting rank to atomic_type_kind is a bit hacky, but makes things
-        * easier here... */
-       if (get_atomic_type_size((atomic_type_kind_t) s_rank)
-                       > get_atomic_type_size((atomic_type_kind_t) u_rank))
+       if (get_atomic_type_size(s_akind) > get_atomic_type_size(u_akind))
                return s_type;
 
-       switch (s_rank) {
-               case ATOMIC_TYPE_INT:      return type_unsigned_int;
-               case ATOMIC_TYPE_LONG:     return type_unsigned_long;
-               case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
+       switch (s_akind) {
+       case ATOMIC_TYPE_INT:      return type_unsigned_int;
+       case ATOMIC_TYPE_LONG:     return type_unsigned_long;
+       case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
 
-               default: panic("invalid atomic type");
+       default: panic("invalid atomic type");
        }
 }
 
@@ -8210,7 +8040,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 {
@@ -8244,7 +8074,7 @@ static bool maybe_negative(expression_t const *const expr)
 {
        switch (is_constant_expression(expr)) {
                case EXPR_CLASS_ERROR:    return false;
-               case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+               case EXPR_CLASS_CONSTANT: return constant_is_negative(expr);
                default:                  return true;
        }
 }
@@ -8563,10 +8393,9 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
 static bool expression_has_effect(const expression_t *const expr)
 {
        switch (expr->kind) {
-               case EXPR_UNKNOWN:                    break;
-               case EXPR_INVALID:                    return true; /* do NOT warn */
+               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 */
@@ -8575,10 +8404,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_LITERAL_CHARACTER:
                case EXPR_LITERAL_WIDE_CHARACTER:
                case EXPR_LITERAL_INTEGER:
-               case EXPR_LITERAL_INTEGER_OCTAL:
-               case EXPR_LITERAL_INTEGER_HEXADECIMAL:
                case EXPR_LITERAL_FLOATINGPOINT:
-               case EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL: return false;
                case EXPR_STRING_LITERAL:             return false;
                case EXPR_WIDE_STRING_LITERAL:        return false;
 
@@ -8634,10 +8460,9 @@ 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_CAST_IMPLICIT:        return true;
                case EXPR_UNARY_ASSUME:               return true;
                case EXPR_UNARY_DELETE:               return true;
                case EXPR_UNARY_DELETE_ARRAY:         return true;
@@ -8705,12 +8530,12 @@ static void semantic_comma(binary_expression_t *expression)
 /**
  * @param prec_r precedence of the right operand
  */
-#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, prec_r, sfunc) \
+#define CREATE_BINEXPR_PARSER(token_kind, binexpression_type, prec_r, sfunc) \
 static expression_t *parse_##binexpression_type(expression_t *left)          \
 {                                                                            \
        expression_t *binexpr = allocate_expression_zero(binexpression_type);    \
        binexpr->binary.left  = left;                                            \
-       eat(token_type);                                                         \
+       eat(token_kind);                                                         \
                                                                              \
        expression_t *right = parse_subexpression(prec_r);                       \
                                                                              \
@@ -8754,12 +8579,8 @@ CREATE_BINEXPR_PARSER(',',                    EXPR_BINARY_COMMA,              PR
 
 static expression_t *parse_subexpression(precedence_t precedence)
 {
-       if (token.type < 0) {
-               return expected_expression_error();
-       }
-
        expression_parser_function_t *parser
-               = &expression_parsers[token.type];
+               = &expression_parsers[token.kind];
        expression_t                 *left;
 
        if (parser->parser != NULL) {
@@ -8770,11 +8591,7 @@ static expression_t *parse_subexpression(precedence_t precedence)
        assert(left != NULL);
 
        while (true) {
-               if (token.type < 0) {
-                       return expected_expression_error();
-               }
-
-               parser = &expression_parsers[token.type];
+               parser = &expression_parsers[token.kind];
                if (parser->infix_parser == NULL)
                        break;
                if (parser->infix_precedence < precedence)
@@ -8783,7 +8600,6 @@ static expression_t *parse_subexpression(precedence_t precedence)
                left = parser->infix_parser(left);
 
                assert(left != NULL);
-               assert(left->kind != EXPR_UNKNOWN);
        }
 
        return left;
@@ -8801,15 +8617,15 @@ static expression_t *parse_expression(void)
  * Register a parser for a prefix-like operator.
  *
  * @param parser      the parser function
- * @param token_type  the token type of the prefix token
+ * @param token_kind  the token type of the prefix token
  */
 static void register_expression_parser(parse_expression_function parser,
-                                       int token_type)
+                                       int token_kind)
 {
-       expression_parser_function_t *entry = &expression_parsers[token_type];
+       expression_parser_function_t *entry = &expression_parsers[token_kind];
 
        if (entry->parser != NULL) {
-               diagnosticf("for token '%k'\n", (token_type_t)token_type);
+               diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
                panic("trying to register multiple expression parsers for a token");
        }
        entry->parser = parser;
@@ -8819,16 +8635,16 @@ static void register_expression_parser(parse_expression_function parser,
  * Register a parser for an infix operator with given precedence.
  *
  * @param parser      the parser function
- * @param token_type  the token type of the infix operator
+ * @param token_kind  the token type of the infix operator
  * @param precedence  the precedence of the operator
  */
 static void register_infix_parser(parse_expression_infix_function parser,
-                                  int token_type, precedence_t precedence)
+                                  int token_kind, precedence_t precedence)
 {
-       expression_parser_function_t *entry = &expression_parsers[token_type];
+       expression_parser_function_t *entry = &expression_parsers[token_kind];
 
        if (entry->infix_parser != NULL) {
-               diagnosticf("for token '%k'\n", (token_type_t)token_type);
+               diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
                panic("trying to register multiple infix expression parsers for a "
                      "token");
        }
@@ -8905,23 +8721,20 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
        asm_argument_t  *result = NULL;
        asm_argument_t **anchor = &result;
 
-       while (token.type == T_STRING_LITERAL || token.type == '[') {
+       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.type != 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.symbol;
-
-                       expect(']', end_error);
                }
 
                argument->constraints = parse_string_literals();
-               expect('(', end_error);
+               expect('(');
                add_anchor_token(')');
                expression_t *expression = parse_expression();
                rem_anchor_token(')');
@@ -8941,7 +8754,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                                size  = get_atomic_type_size(akind);
                                        } else {
                                                flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                               size  = get_atomic_type_size(get_intptr_kind());
+                                               size  = get_type_size(type_void_ptr);
                                        }
 
                                        do {
@@ -8957,7 +8770,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                                        value_size  = get_atomic_type_size(value_akind);
                                                } else if (value_kind == TYPE_POINTER) {
                                                        value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                                       value_size  = get_atomic_type_size(get_intptr_kind());
+                                                       value_size  = get_type_size(type_void_ptr);
                                                } else {
                                                        break;
                                                }
@@ -8983,7 +8796,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);
 
@@ -8995,8 +8808,6 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
        }
 
        return result;
-end_error:
-       return NULL;
 }
 
 /**
@@ -9007,7 +8818,7 @@ static asm_clobber_t *parse_asm_clobbers(void)
        asm_clobber_t *result  = NULL;
        asm_clobber_t **anchor = &result;
 
-       while (token.type == T_STRING_LITERAL) {
+       while (token.kind == T_STRING_LITERAL) {
                asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
                clobber->clobber       = parse_string_literals();
 
@@ -9034,9 +8845,9 @@ 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.type != T_STRING_LITERAL) {
+       if (token.kind != T_STRING_LITERAL) {
                parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
                goto end_of_asm;
        }
@@ -9065,8 +8876,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
@@ -9075,17 +8886,15 @@ end_of_asm:
        }
 
        return statement;
-end_error:
-       return create_invalid_statement();
 }
 
 static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
 {
        statement_t *inner_stmt;
-       switch (token.type) {
+       switch (token.kind) {
                case '}':
                        errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
-                       inner_stmt = create_invalid_statement();
+                       inner_stmt = create_error_statement();
                        break;
 
                case ';':
@@ -9101,7 +8910,8 @@ static statement_t *parse_label_inner_statement(statement_t const *const label,
 
                default:
                        inner_stmt = parse_statement();
-                       /* ISO/IEC 14882:1998(E) Â§6:1/§6.7  Declarations are statements */
+                       /* ISO/IEC  9899:1999(E) Â§6.8:1/6.8.2:1  Declarations are no statements */
+                       /* ISO/IEC 14882:1998(E) Â§6:1/§6.7       Declarations are statements */
                        if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
                                errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
                        }
@@ -9119,8 +8929,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) {
@@ -9136,7 +8962,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) {
@@ -9158,8 +8992,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) {
@@ -9190,7 +9024,7 @@ end_error:
 
        statement->case_label.statement = parse_label_inner_statement(statement, "case label");
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 }
 
@@ -9205,8 +9039,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;
@@ -9230,7 +9063,7 @@ end_error:
 
        statement->case_label.statement = parse_label_inner_statement(statement, "default label");
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 }
 
@@ -9258,16 +9091,45 @@ static statement_t *parse_label_statement(void)
 
        eat(':');
 
+       if (token.kind == T___attribute__ && !(c_mode & _CXX)) {
+               parse_attributes(NULL); // TODO process attributes
+       }
+
        statement->label.statement = parse_label_inner_statement(statement, "label");
 
        /* remember the labels in a list for later checking */
        *label_anchor = &statement->label;
        label_anchor  = &statement->label.next;
 
-       POP_PARENT;
+       POP_PARENT();
        return statement;
 }
 
+static statement_t *parse_inner_statement(void)
+{
+       statement_t *const stmt = parse_statement();
+       /* ISO/IEC  9899:1999(E) Â§6.8:1/6.8.2:1  Declarations are no statements */
+       /* ISO/IEC 14882:1998(E) Â§6:1/§6.7       Declarations are statements */
+       if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+               errorf(&stmt->base.source_position, "declaration as inner statement, use {}");
+       }
+       return stmt;
+}
+
+/**
+ * Parse an 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.
  */
@@ -9278,37 +9140,40 @@ 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_statement();
+       statement_t *const true_stmt = parse_inner_statement();
        statement->ifs.true_statement = true_stmt;
        rem_anchor_token(T_else);
 
+       if (true_stmt->kind == STATEMENT_EMPTY) {
+               warningf(WARN_EMPTY_BODY, HERE,
+                       "suggest braces around empty body in an â€˜if’ statement");
+       }
+
        if (next_if(T_else)) {
-               statement->ifs.false_statement = parse_statement();
+               statement->ifs.false_statement = parse_inner_statement();
+
+               if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) {
+                       warningf(WARN_EMPTY_BODY, HERE,
+                                       "suggest braces around empty body in an â€˜if’ statement");
+               }
        } else if (true_stmt->kind == STATEMENT_IF &&
                        true_stmt->ifs.false_statement != NULL) {
                source_position_t const *const pos = &true_stmt->base.source_position;
                warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
        }
 
-       POP_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
 }
 
@@ -9365,15 +9230,13 @@ 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);
-               if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+               if (get_akind_rank(get_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
                        warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int);
                }
        } else if (is_type_valid(type)) {
@@ -9382,12 +9245,10 @@ 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;
-       statement->switchs.body = parse_statement();
+       statement->switchs.body = parse_inner_statement();
        current_switch          = rem;
 
        if (statement->switchs.default_label == NULL) {
@@ -9395,11 +9256,9 @@ static statement_t *parse_switch(void)
        }
        check_enum_cases(&statement->switchs);
 
-       POP_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 static statement_t *parse_loop_body(statement_t *const loop)
@@ -9407,7 +9266,7 @@ static statement_t *parse_loop_body(statement_t *const loop)
        statement_t *const rem = current_loop;
        current_loop = loop;
 
-       statement_t *const body = parse_statement();
+       statement_t *const body = parse_inner_statement();
 
        current_loop = rem;
        return body;
@@ -9423,25 +9282,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_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 /**
@@ -9454,29 +9307,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_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 /**
@@ -9488,18 +9335,13 @@ static statement_t *parse_for(void)
 
        eat(T_for);
 
-       expect('(', end_error1);
-       add_anchor_token(')');
-
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->fors.scope);
 
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&statement->fors.scope);
+       expect('(');
+       add_anchor_token(')');
 
-       bool old_gcc_extension = in_gcc_extension;
-       while (next_if(T___extension__)) {
-               in_gcc_extension = true;
-       }
+       PUSH_EXTENSION();
 
        if (next_if(';')) {
        } else if (is_declaration_specifier(&token)) {
@@ -9513,11 +9355,12 @@ 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(';');
        }
-       in_gcc_extension = old_gcc_extension;
 
-       if (token.type != ';') {
+       POP_EXTENSION();
+
+       if (token.kind != ';') {
                add_anchor_token(';');
                expression_t *const cond = parse_expression();
                statement->fors.condition = cond;
@@ -9527,8 +9370,8 @@ static statement_t *parse_for(void)
                mark_vars_read(cond, NULL);
                rem_anchor_token(';');
        }
-       expect(';', end_error2);
-       if (token.type != ')') {
+       expect(';');
+       if (token.kind != ')') {
                expression_t *const step = parse_expression();
                statement->fors.step = step;
                mark_vars_read(step, ENT_ANY);
@@ -9536,27 +9379,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);
 
-       assert(current_scope == &statement->fors.scope);
-       scope_pop(old_scope);
-       environment_pop_to(top);
-
-       POP_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
-
-end_error2:
-       POP_PARENT;
-       rem_anchor_token(')');
-       assert(current_scope == &statement->fors.scope);
-       scope_pop(old_scope);
-       environment_pop_to(top);
-       /* fallthrough */
-
-end_error1:
-       return create_invalid_statement();
 }
 
 /**
@@ -9564,10 +9393,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);
 
@@ -9585,27 +9416,29 @@ static statement_t *parse_goto(void)
                        expression = create_implicit_cast(expression, type_void_ptr);
                }
 
-               statement->gotos.expression = expression;
-       } else if (token.type == 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_invalid_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;
 }
 
@@ -9621,9 +9454,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;
 }
 
@@ -9639,9 +9470,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;
 }
 
@@ -9657,9 +9486,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;
 }
 
@@ -9714,6 +9541,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.
  */
@@ -9723,7 +9559,7 @@ static statement_t *parse_return(void)
        eat(T_return);
 
        expression_t *return_value = NULL;
-       if (token.type != ';') {
+       if (token.kind != ';') {
                return_value = parse_expression();
                mark_vars_read(return_value, NULL);
        }
@@ -9736,24 +9572,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);
@@ -9768,20 +9594,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;
 }
 
@@ -9819,9 +9638,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;
 }
 
@@ -9841,13 +9658,10 @@ static statement_t *parse_ms_try_statment(void)
        statement->ms_try.try_statement = parse_compound_statement(false);
        current_try = rem;
 
-       POP_PARENT;
+       POP_PARENT();
 
        if (next_if(T___except)) {
-               expect('(', end_error);
-               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);
@@ -9857,18 +9671,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_invalid_statement();
        }
+       statement->ms_try.final_statement = parse_compound_statement(false);
        return statement;
-end_error:
-       return create_invalid_statement();
 }
 
 static statement_t *parse_empty_statement(void)
@@ -9889,20 +9696,18 @@ static statement_t *parse_local_label_declaration(void)
        entity_t *end     = NULL;
        entity_t **anchor = &begin;
        do {
-               if (token.type != 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.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.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;
@@ -9910,9 +9715,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;
@@ -9926,8 +9730,8 @@ static void parse_namespace_definition(void)
        entity_t *entity = NULL;
        symbol_t *symbol = NULL;
 
-       if (token.type == T_IDENTIFIER) {
-               symbol = token.symbol;
+       if (token.kind == T_IDENTIFIER) {
+               symbol = token.identifier.symbol;
                next_token();
 
                entity = get_entity(symbol, NAMESPACE_NORMAL);
@@ -9935,7 +9739,7 @@ static void parse_namespace_definition(void)
                                && entity->kind != ENTITY_NAMESPACE
                                && entity->base.parent_scope == current_scope) {
                        if (is_entity_valid(entity)) {
-                               error_redefined_as_different_kind(&token.source_position,
+                               error_redefined_as_different_kind(&token.base.source_position,
                                                entity, ENTITY_NAMESPACE);
                        }
                        entity = NULL;
@@ -9943,12 +9747,11 @@ static void parse_namespace_definition(void)
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
-               entity->base.source_position = token.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.type == '=') {
+       if (token.kind == '=') {
                /* TODO: parse namespace alias */
                panic("namespace alias definition not supported yet");
        }
@@ -9956,22 +9759,17 @@ static void parse_namespace_definition(void)
        environment_push(entity);
        append_entity(current_scope, entity);
 
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&entity->namespacee.members);
-
-       entity_t     *old_current_entity = current_entity;
-       current_entity = entity;
+       PUSH_SCOPE(&entity->namespacee.members);
+       PUSH_CURRENT_ENTITY(entity);
 
-       expect('{', end_error);
+       add_anchor_token('}');
+       expect('{');
        parse_externals();
-       expect('}', end_error);
+       rem_anchor_token('}');
+       expect('}');
 
-end_error:
-       assert(current_scope == &entity->namespacee.members);
-       assert(current_entity == entity);
-       current_entity = old_current_entity;
-       scope_pop(old_scope);
-       environment_pop_to(top);
+       POP_CURRENT_ENTITY();
+       POP_SCOPE();
 }
 
 /**
@@ -9981,16 +9779,14 @@ end_error:
  */
 static statement_t *intern_parse_statement(void)
 {
-       statement_t *statement = NULL;
-
        /* declaration or statement */
-       add_anchor_token(';');
-       switch (token.type) {
+       statement_t *statement;
+       switch (token.kind) {
        case T_IDENTIFIER: {
-               token_type_t la1_type = (token_type_t)look_ahead(1)->type;
+               token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
                if (la1_type == ':') {
                        statement = parse_label_statement();
-               } else if (is_typedef_symbol(token.symbol)) {
+               } else if (is_typedef_symbol(token.identifier.symbol)) {
                        statement = parse_declaration_statement();
                } else {
                        /* it's an identifier, the grammar says this must be an
@@ -10000,7 +9796,7 @@ static statement_t *intern_parse_statement(void)
                        switch (la1_type) {
                        case '&':
                        case '*':
-                               if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) {
+                               if (get_entity(token.identifier.symbol, NAMESPACE_NORMAL) != NULL) {
                        default:
                                        statement = parse_expression_statement();
                                } else {
@@ -10014,15 +9810,14 @@ static statement_t *intern_parse_statement(void)
                break;
        }
 
-       case T___extension__:
+       case T___extension__: {
                /* This can be a prefix to a declaration or an expression statement.
                 * We simply eat it now and parse the rest with tail recursion. */
-               while (next_if(T___extension__)) {}
-               bool old_gcc_extension = in_gcc_extension;
-               in_gcc_extension       = true;
+               PUSH_EXTENSION();
                statement = intern_parse_statement();
-               in_gcc_extension = old_gcc_extension;
+               POP_EXTENSION();
                break;
+       }
 
        DECLARATION_START
                statement = parse_declaration_statement();
@@ -10055,15 +9850,10 @@ static statement_t *intern_parse_statement(void)
 
        default:
                errorf(HERE, "unexpected token %K while parsing statement", &token);
-               statement = create_invalid_statement();
-               if (!at_anchor())
-                       next_token();
+               statement = create_error_statement();
+               eat_until_anchor();
                break;
        }
-       rem_anchor_token(';');
-
-       assert(statement != NULL
-                       && statement->base.source_position.input_name != NULL);
 
        return statement;
 }
@@ -10096,6 +9886,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE(&statement->compound.scope);
 
        eat('{');
        add_anchor_token('}');
@@ -10107,6 +9898,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);
@@ -10188,23 +9980,12 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token(T_wchar_t);
        add_anchor_token(T_while);
 
-       size_t const  top       = environment_top();
-       scope_t      *old_scope = scope_push(&statement->compound.scope);
-
        statement_t **anchor            = &statement->compound.statements;
        bool          only_decls_so_far = true;
-       while (token.type != '}') {
-               if (token.type == 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 (is_invalid_statement(sub_statement)) {
-                       /* an error occurred. if we are at an anchor, return */
-                       if (at_anchor())
-                               goto end_error;
-                       continue;
+               if (sub_statement->kind == STATEMENT_ERROR) {
+                       break;
                }
 
                if (sub_statement->kind != STATEMENT_DECLARATION) {
@@ -10215,13 +9996,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)) {
@@ -10241,7 +10018,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);
@@ -10322,6 +10098,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('*');
@@ -10329,11 +10106,9 @@ end_error:
        rem_anchor_token('&');
        rem_anchor_token('!');
        rem_anchor_token('}');
-       assert(current_scope == &statement->compound.scope);
-       scope_pop(old_scope);
-       environment_pop_to(top);
 
-       POP_PARENT;
+       POP_SCOPE();
+       POP_PARENT();
        return statement;
 }
 
@@ -10380,16 +10155,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)
@@ -10401,47 +10180,45 @@ 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);
-               new_linkage = LINKAGE_INVALID;
+               new_linkage = LINKAGE_C;
        }
        current_linkage = new_linkage;
 
        if (next_if('{')) {
                parse_externals();
-               expect('}', end_error);
+               expect('}');
        } else {
                parse_external();
        }
 
-end_error:
        assert(current_linkage == new_linkage);
        current_linkage = old_linkage;
 }
 
 static void parse_external(void)
 {
-       switch (token.type) {
+       switch (token.kind) {
+               case T_extern:
+                       if (look_ahead(1)->kind == T_STRING_LITERAL) {
+                               parse_linkage_specification();
+                       } else {
                DECLARATION_START_NO_EXTERN
                case T_IDENTIFIER:
                case T___extension__:
                /* tokens below are for implicit int */
-               case '&': /* & x; -> int& x; (and error later, because C++ has no
-                            implicit int) */
-               case '*': /* * x; -> int* x; */
-               case '(': /* (x); -> int (x); */
-                       parse_external_declaration();
-                       return;
-
-               case T_extern:
-                       if (look_ahead(1)->type == T_STRING_LITERAL) {
-                               parse_linkage_specification();
-                       } else {
+               case '&':  /* & x; -> int& x; (and error later, because C++ has no
+                             implicit int) */
+               case '*':  /* * x; -> int* x; */
+               case '(':  /* (x); -> int (x); */
+                               PUSH_EXTENSION();
                                parse_external_declaration();
+                               POP_EXTENSION();
                        }
                        return;
 
@@ -10455,7 +10232,7 @@ static void parse_external(void)
 
                case ';':
                        if (!strict_mode) {
-                               warningf(WARN_OTHER, HERE, "stray ';' outside of function");
+                               warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function");
                                next_token();
                                return;
                        }
@@ -10463,8 +10240,8 @@ static void parse_external(void)
 
                default:
                        errorf(HERE, "stray %K outside of function", &token);
-                       if (token.type == '(' || token.type == '{' || token.type == '[')
-                               eat_until_matching_token(token.type);
+                       if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+                               eat_until_matching_token(token.kind);
                        next_token();
                        return;
        }
@@ -10477,14 +10254,14 @@ static void parse_externals(void)
 
 #ifndef NDEBUG
        /* make a copy of the anchor set, so we can check if it is restored after parsing */
-       unsigned char token_anchor_copy[T_LAST_TOKEN];
+       unsigned short token_anchor_copy[T_LAST_TOKEN];
        memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
 #endif
 
-       while (token.type != T_EOF && token.type != '}') {
+       while (token.kind != T_EOF && token.kind != '}') {
 #ifndef NDEBUG
                for (int i = 0; i < T_LAST_TOKEN; ++i) {
-                       unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
+                       unsigned short count = token_anchor_set[i] - token_anchor_copy[i];
                        if (count != 0) {
                                /* the anchor set and its copy differs */
                                internal_errorf(HERE, "Leaked anchor token %k %d times", i, count);
@@ -10513,12 +10290,12 @@ static void parse_translation_unit(void)
        while (true) {
                parse_externals();
 
-               if (token.type == T_EOF)
+               if (token.kind == T_EOF)
                        break;
 
                errorf(HERE, "stray %K outside of function", &token);
-               if (token.type == '(' || token.type == '{' || token.type == '[')
-                       eat_until_matching_token(token.type);
+               if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+                       eat_until_matching_token(token.kind);
                next_token();
        }
 }
@@ -10600,8 +10377,10 @@ static void complete_incomplete_arrays(void)
        }
 }
 
-void prepare_main_collect2(entity_t *entity)
+static void prepare_main_collect2(entity_t *const entity)
 {
+       PUSH_SCOPE(&entity->function.statement->compound.scope);
+
        // create call to __main
        symbol_t *symbol         = symbol_table_insert("__main");
        entity_t *subsubmain_ent
@@ -10628,6 +10407,8 @@ void prepare_main_collect2(entity_t *entity)
 
        expr_statement->base.next = compounds->statements;
        compounds->statements     = expr_statement;
+
+       POP_SCOPE();
 }
 
 void parse(void)