specify error label for expect macro, fix wrong anchor set when parsing for;
[cparser] / parser.c
index 5ff6397..7e77c60 100644 (file)
--- a/parser.c
+++ b/parser.c
 #include "adt/error.h"
 #include "adt/array.h"
 
-/** if wchar_t is equal to unsigned short. */
-bool opt_short_wchar_t =
-#ifdef _WIN32
-       true;
-#else
-       false;
-#endif
-
 //#define PRINT_TOKENS
 #define MAX_LOOKAHEAD 2
 
 typedef struct {
-       entity_t    *old_entity;
-       symbol_t    *symbol;
-       namespace_t  namespc;
+       entity_t           *old_entity;
+       symbol_t           *symbol;
+       entity_namespace_t  namespc;
 } stack_entry_t;
 
 typedef struct argument_list_t argument_list_t;
@@ -84,8 +76,9 @@ struct declaration_specifiers_t {
        source_position_t  source_position;
        storage_class_t    storage_class;
        unsigned char      alignment;         /**< Alignment, 0 if not set. */
-       bool               is_inline : 1;
-       bool               deprecated : 1;
+       bool               is_inline    : 1;
+       bool               thread_local : 1;  /**< GCC __thread */
+       bool               deprecated   : 1;
        decl_modifiers_t   modifiers;         /**< declaration modifiers */
        gnu_attribute_t   *gnu_attributes;    /**< list of GNU attributes */
        const char        *deprecated_string; /**< can be set if declaration was marked deprecated. */
@@ -105,39 +98,47 @@ typedef struct parse_initializer_env_t {
        bool        must_be_constant;
 } parse_initializer_env_t;
 
+/**
+ * Capture a MS __base extension.
+ */
+typedef struct based_spec_t {
+       source_position_t  source_position;
+       variable_t        *base_variable;
+} based_spec_t;
+
 typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition);
 
 /** The current token. */
-static token_t             token;
+static token_t              token;
 /** The lookahead ring-buffer. */
-static token_t             lookahead_buffer[MAX_LOOKAHEAD];
+static token_t              lookahead_buffer[MAX_LOOKAHEAD];
 /** Position of the next token in the lookahead buffer. */
-static int                 lookahead_bufpos;
-static stack_entry_t      *environment_stack = NULL;
-static stack_entry_t      *label_stack       = NULL;
-static stack_entry_t      *local_label_stack = NULL;
-/** The global file scope. */
-static scope_t            *file_scope        = NULL;
-/** The current scope. */
-static scope_t            *scope             = NULL;
+static int                  lookahead_bufpos;
+static stack_entry_t       *environment_stack = NULL;
+static stack_entry_t       *label_stack       = NULL;
+static scope_t             *file_scope        = NULL;
+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_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 goto_statement_t   *goto_first        = NULL;
-static goto_statement_t   *goto_last         = NULL;
-static label_statement_t  *label_first       = NULL;
-static label_statement_t  *label_last        = NULL;
+static function_t          *current_function  = 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 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;
+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;
+static bool                 in_type_prop      = false;
 /** true in we are in a __extension__ context. */
-static bool                in_gcc_extension  = false;
-static struct obstack      temp_obst;
+static bool                 in_gcc_extension  = false;
+static struct obstack       temp_obst;
+static entity_t            *anonymous_entity;
+static declaration_t      **incomplete_arrays;
 
 
 #define PUSH_PARENT(stmt)                          \
@@ -185,18 +186,31 @@ static statement_t *parse_statement(void);
 static expression_t *parse_sub_expression(precedence_t);
 static expression_t *parse_expression(void);
 static type_t       *parse_typename(void);
+static void          parse_externals(void);
+static void          parse_external(void);
 
 static void parse_compound_type_entries(compound_t *compound_declaration);
+
+typedef enum declarator_flags_t {
+       DECL_FLAGS_NONE             = 0,
+       DECL_MAY_BE_ABSTRACT        = 1U << 0,
+       DECL_CREATE_COMPOUND_MEMBER = 1U << 1,
+       DECL_IS_PARAMETER           = 1U << 2
+} declarator_flags_t;
+
 static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
-                                  bool may_be_abstract,
-                                  bool create_compound_member);
+                                  declarator_flags_t flags);
+
 static entity_t *record_entity(entity_t *entity, bool is_definition);
 
 static void semantic_comparison(binary_expression_t *expression);
 
-#define STORAGE_CLASSES     \
+#define STORAGE_CLASSES       \
+       STORAGE_CLASSES_NO_EXTERN \
+       case T_extern:
+
+#define STORAGE_CLASSES_NO_EXTERN \
        case T_typedef:         \
-       case T_extern:          \
        case T_static:          \
        case T_auto:            \
        case T_register:        \
@@ -210,15 +224,10 @@ static void semantic_comparison(binary_expression_t *expression);
        case T__forceinline:    \
        case T___attribute__:
 
-#ifdef PROVIDE_COMPLEX
 #define COMPLEX_SPECIFIERS  \
        case T__Complex:
 #define IMAGINARY_SPECIFIERS \
        case T__Imaginary:
-#else
-#define COMPLEX_SPECIFIERS
-#define IMAGINARY_SPECIFIERS
-#endif
 
 #define TYPE_SPECIFIERS       \
        case T__Bool:             \
@@ -246,6 +255,11 @@ static void semantic_comparison(binary_expression_t *expression);
        TYPE_QUALIFIERS         \
        TYPE_SPECIFIERS
 
+#define DECLARATION_START_NO_EXTERN \
+       STORAGE_CLASSES_NO_EXTERN       \
+       TYPE_QUALIFIERS                 \
+       TYPE_SPECIFIERS
+
 #define TYPENAME_START      \
        TYPE_QUALIFIERS         \
        TYPE_SPECIFIERS
@@ -314,11 +328,17 @@ static void *allocate_ast_zero(size_t size)
        return res;
 }
 
+/**
+ * Returns the size of an entity node.
+ *
+ * @param kind  the entity kind
+ */
 static size_t get_entity_struct_size(entity_kind_t kind)
 {
        static const size_t sizes[] = {
                [ENTITY_VARIABLE]        = sizeof(variable_t),
-               [ENTITY_COMPOUND_MEMBER] = sizeof(variable_t),
+               [ENTITY_PARAMETER]       = sizeof(parameter_t),
+               [ENTITY_COMPOUND_MEMBER] = sizeof(compound_member_t),
                [ENTITY_FUNCTION]        = sizeof(function_t),
                [ENTITY_TYPEDEF]         = sizeof(typedef_t),
                [ENTITY_STRUCT]          = sizeof(compound_t),
@@ -326,13 +346,18 @@ static size_t get_entity_struct_size(entity_kind_t kind)
                [ENTITY_ENUM]            = sizeof(enum_t),
                [ENTITY_ENUM_VALUE]      = sizeof(enum_value_t),
                [ENTITY_LABEL]           = sizeof(label_t),
-               [ENTITY_LOCAL_LABEL]     = sizeof(label_t)
+               [ENTITY_LOCAL_LABEL]     = sizeof(label_t),
+               [ENTITY_NAMESPACE]       = sizeof(namespace_t)
        };
-       assert(kind <= sizeof(sizes) / sizeof(sizes[0]));
+       assert(kind < sizeof(sizes) / sizeof(sizes[0]));
        assert(sizes[kind] != 0);
        return sizes[kind];
 }
 
+/**
+ * Allocate an entity of given kind and initialize all
+ * fields with zero.
+ */
 static entity_t *allocate_entity_zero(entity_kind_t kind)
 {
        size_t    size   = get_entity_struct_size(kind);
@@ -370,7 +395,7 @@ static size_t get_statement_struct_size(statement_kind_t kind)
                [STATEMENT_MS_TRY]      = sizeof(ms_try_statement_t),
                [STATEMENT_LEAVE]       = sizeof(leave_statement_t)
        };
-       assert(kind <= sizeof(sizes) / sizeof(sizes[0]));
+       assert(kind < sizeof(sizes) / sizeof(sizes[0]));
        assert(sizes[kind] != 0);
        return sizes[kind];
 }
@@ -417,14 +442,15 @@ static size_t get_expression_struct_size(expression_kind_t kind)
        if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) {
                return sizes[EXPR_BINARY_FIRST];
        }
-       assert(kind <= sizeof(sizes) / sizeof(sizes[0]));
+       assert(kind < sizeof(sizes) / sizeof(sizes[0]));
        assert(sizes[kind] != 0);
        return sizes[kind];
 }
 
 /**
  * Allocate a statement node of given kind and initialize all
- * fields with zero.
+ * fields with zero. Sets its source position to the position
+ * of the current token.
  */
 static statement_t *allocate_statement_zero(statement_kind_t kind)
 {
@@ -453,7 +479,8 @@ static expression_t *allocate_expression_zero(expression_kind_t kind)
 }
 
 /**
- * Creates a new invalid expression.
+ * Creates a new invalid expression at the source position
+ * of the current token.
  */
 static expression_t *create_invalid_expression(void)
 {
@@ -575,14 +602,6 @@ static size_t label_top(void)
        return ARR_LEN(label_stack);
 }
 
-/**
- * Returns the index of the top element of the local label stack.
- */
-static size_t local_label_top(void)
-{
-       return ARR_LEN(local_label_stack);
-}
-
 /**
  * Return the next token.
  */
@@ -611,7 +630,7 @@ static inline const token_t *look_ahead(int num)
 }
 
 /**
- * Adds a token to the token anchor set (a multi-set).
+ * Adds a token type to the token type anchor set (a multi-set).
  */
 static void add_anchor_token(int token_type)
 {
@@ -619,6 +638,10 @@ static void add_anchor_token(int token_type)
        ++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);
@@ -627,6 +650,9 @@ static int save_and_reset_anchor_state(int token_type)
        return count;
 }
 
+/**
+ * Restore the number of token types to the given count.
+ */
 static void restore_anchor_state(int token_type, int count)
 {
        assert(0 <= token_type && token_type < T_LAST_TOKEN);
@@ -634,7 +660,7 @@ static void restore_anchor_state(int token_type, int count)
 }
 
 /**
- * Remove a token from the token anchor set (a multi-set).
+ * Remove a token type from the token type anchor set (a multi-set).
  */
 static void rem_anchor_token(int token_type)
 {
@@ -643,6 +669,10 @@ static void rem_anchor_token(int token_type)
        --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)
 {
        if (token.type < 0)
@@ -651,7 +681,7 @@ static bool at_anchor(void)
 }
 
 /**
- * Eat tokens until a matching token is found.
+ * Eat tokens until a matching token type is found.
  */
 static void eat_until_matching_token(int type)
 {
@@ -716,6 +746,9 @@ static void eat_until_anchor(void)
        }
 }
 
+/**
+ * Eat a whole block from input tokens.
+ */
 static void eat_block(void)
 {
        eat_until_matching_token('{');
@@ -743,15 +776,6 @@ void parse_error_expected(const char *message, ...)
        va_end(ap);
 }
 
-/**
- * Report a type error.
- */
-static void type_error(const char *msg, const source_position_t *source_position,
-                       type_t *type)
-{
-       errorf(source_position, "%s, but found type '%T'", msg, type);
-}
-
 /**
  * Report an incompatible type.
  */
@@ -763,11 +787,11 @@ static void type_error_incompatible(const char *msg,
 }
 
 /**
- * Expect the the current token is the expected token.
+ * Expect the current token is the expected token.
  * If not, generate an error, eat the current statement,
  * and goto the end_error label.
  */
-#define expect(expected)                                  \
+#define expect(expected, error_label)                     \
        do {                                                  \
                if (UNLIKELY(token.type != (expected))) {         \
                        parse_error_expected(NULL, (expected), NULL); \
@@ -776,32 +800,42 @@ static void type_error_incompatible(const char *msg,
                        if (token.type == expected)                   \
                                next_token();                             \
                        rem_anchor_token(expected);                   \
-                       goto end_error;                               \
+                       goto error_label;                             \
                }                                                 \
                next_token();                                     \
        } while (0)
 
-static void scope_push(scope_t *new_scope)
+/**
+ * Push a given scope on the scope stack and make it the
+ * current scope
+ */
+static scope_t *scope_push(scope_t *new_scope)
 {
-       if (scope != NULL) {
-               new_scope->depth = scope->depth + 1;
+       if (current_scope != NULL) {
+               new_scope->depth = current_scope->depth + 1;
        }
-       new_scope->parent = scope;
-       scope             = new_scope;
+
+       scope_t *old_scope = current_scope;
+       current_scope      = new_scope;
+       return old_scope;
 }
 
-static void scope_pop(void)
+/**
+ * Pop the current scope from the scope stack.
+ */
+static void scope_pop(scope_t *old_scope)
 {
-       scope = scope->parent;
+       current_scope = old_scope;
 }
 
 /**
  * Search an entity by its symbol in a given namespace.
  */
-static entity_t *get_entity(const symbol_t *const symbol, namespace_t namespc)
+static entity_t *get_entity(const symbol_t *const symbol,
+                            namespace_tag_t namespc)
 {
        entity_t *entity = symbol->entity;
-       for; entity != NULL; entity = entity->base.symbol_next) {
+       for (; entity != NULL; entity = entity->base.symbol_next) {
                if (entity->base.namespc == namespc)
                        return entity;
        }
@@ -815,8 +849,8 @@ static entity_t *get_entity(const symbol_t *const symbol, namespace_t namespc)
  */
 static void stack_push(stack_entry_t **stack_ptr, entity_t *entity)
 {
-       symbol_t    *symbol  = entity->base.symbol;
-       namespace_t  namespc = entity->base.namespc;
+       symbol_t           *symbol  = entity->base.symbol;
+       entity_namespace_t  namespc = entity->base.namespc;
        assert(namespc != NAMESPACE_INVALID);
 
        /* replace/add entity into entity list of the symbol */
@@ -865,18 +899,6 @@ static void label_push(entity_t *label)
        stack_push(&label_stack, label);
 }
 
-/**
- * Push a declaration of the local label stack.
- *
- * @param declaration  the declaration
- */
-static void local_label_push(entity_t *label)
-{
-       assert(label->base.parent_scope != NULL);
-       label->base.parent_scope = scope;
-       stack_push(&local_label_stack, label);
-}
-
 /**
  * pops symbols from the environment stack until @p new_top is the top element
  */
@@ -890,12 +912,12 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
        if (new_top == top)
                return;
 
-       for(i = top; i > new_top; --i) {
+       for (i = top; i > new_top; --i) {
                stack_entry_t *entry = &stack[i - 1];
 
-               entity_t    *old_entity = entry->old_entity;
-               symbol_t    *symbol     = entry->symbol;
-               namespace_t  namespc    = entry->namespc;
+               entity_t           *old_entity = entry->old_entity;
+               symbol_t           *symbol     = entry->symbol;
+               entity_namespace_t  namespc    = entry->namespc;
 
                /* replace with old_entity/remove */
                entity_t **anchor;
@@ -943,23 +965,14 @@ static void label_pop_to(size_t new_top)
        stack_pop_to(&label_stack, new_top);
 }
 
-/**
- * Pop all entries from the local label stack until the new_top
- * is reached.
- *
- * @param new_top  the new stack top
- */
-static void local_label_pop_to(size_t new_top)
-{
-       stack_pop_to(&local_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)
 {
        assert(!is_typeref(type));
@@ -975,6 +988,12 @@ static int get_rank(const type_t *type)
        return get_akind_rank(type->atomic.akind);
 }
 
+/**
+ * Do integer promotion for a given type.
+ *
+ * @param type  the type to promote
+ * @return the promoted type
+ */
 static type_t *promote_integer(type_t *type)
 {
        if (type->kind == TYPE_BITFIELD)
@@ -1004,7 +1023,9 @@ static expression_t *create_cast_expression(expression_t *expression,
 }
 
 /**
- * Check if a given expression represents the 0 pointer constant.
+ * Check if a given expression represents a null pointer constant.
+ *
+ * @param expression  the expression to check
  */
 static bool is_null_pointer_constant(const expression_t *expression)
 {
@@ -1185,7 +1206,7 @@ static expression_t *parse_constant_expression(void)
 
        if (!is_constant_expression(result)) {
                errorf(&result->base.source_position,
-                      "expression '%E' is not constant\n", result);
+                      "expression '%E' is not constant", result);
        }
 
        return result;
@@ -1196,25 +1217,6 @@ static expression_t *parse_assignment_expression(void)
        return parse_sub_expression(PREC_ASSIGNMENT);
 }
 
-static type_t *make_global_typedef(const char *name, type_t *type)
-{
-       symbol_t *const symbol = symbol_table_insert(name);
-
-       entity_t *const entity       = allocate_entity_zero(ENTITY_TYPEDEF);
-       entity->base.symbol          = symbol;
-       entity->base.source_position = builtin_source_position;
-       entity->base.namespc         = NAMESPACE_NORMAL;
-       entity->typedefe.type        = type;
-       entity->typedefe.builtin     = true;
-
-       record_entity(entity, false);
-
-       type_t *typedef_type            = allocate_type_zero(TYPE_TYPEDEF);
-       typedef_type->typedeft.typedefe = &entity->typedefe;
-
-       return typedef_type;
-}
-
 static string_t parse_string_literals(void)
 {
        assert(token.type == T_STRING_LITERAL);
@@ -1315,7 +1317,7 @@ static int strcmp_underscore(const char *s1, const char *s2)
 }
 
 /**
- * Allocate a new gnu temporal attribute.
+ * Allocate a new gnu temporal attribute of given kind.
  */
 static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind)
 {
@@ -1329,7 +1331,7 @@ static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind)
 }
 
 /**
- * parse one constant expression argument.
+ * Parse one constant expression argument of the given attribute.
  */
 static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute)
 {
@@ -1337,7 +1339,7 @@ static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute)
        add_anchor_token(')');
        expression = parse_constant_expression();
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
        attribute->u.argument = fold_constant(expression);
        return;
 end_error:
@@ -1345,7 +1347,7 @@ end_error:
 }
 
 /**
- * parse a list of constant expressions arguments.
+ * Parse a list of constant expressions arguments of the given attribute.
  */
 static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute)
 {
@@ -1367,14 +1369,14 @@ static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute)
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
        return;
 end_error:
        attribute->invalid = true;
 }
 
 /**
- * parse one string literal argument.
+ * Parse one string literal argument of the given attribute.
  */
 static void parse_gnu_attribute_string_arg(gnu_attribute_t *attribute,
                                            string_t *string)
@@ -1387,14 +1389,14 @@ static void parse_gnu_attribute_string_arg(gnu_attribute_t *attribute,
        }
        *string = parse_string_literals();
        rem_anchor_token('(');
-       expect(')');
+       expect(')', end_error);
        return;
 end_error:
        attribute->invalid = true;
 }
 
 /**
- * parse one tls model.
+ * Parse one tls model of the given attribute.
  */
 static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute)
 {
@@ -1407,7 +1409,7 @@ static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute)
        string_t string = { NULL, 0 };
        parse_gnu_attribute_string_arg(attribute, &string);
        if (string.begin != NULL) {
-               for(size_t i = 0; i < 4; ++i) {
+               for (size_t i = 0; i < 4; ++i) {
                        if (strcmp(tls_models[i], string.begin) == 0) {
                                attribute->u.value = i;
                                return;
@@ -1419,7 +1421,7 @@ static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute)
 }
 
 /**
- * parse one tls model.
+ * Parse one tls model of the given attribute.
  */
 static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute)
 {
@@ -1432,7 +1434,7 @@ static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute)
        string_t string = { NULL, 0 };
        parse_gnu_attribute_string_arg(attribute, &string);
        if (string.begin != NULL) {
-               for(size_t i = 0; i < 4; ++i) {
+               for (size_t i = 0; i < 4; ++i) {
                        if (strcmp(visibilities[i], string.begin) == 0) {
                                attribute->u.value = i;
                                return;
@@ -1444,7 +1446,7 @@ static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute)
 }
 
 /**
- * parse one (code) model.
+ * Parse one (code) model of the given attribute.
  */
 static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute)
 {
@@ -1456,7 +1458,7 @@ static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute)
        string_t string = { NULL, 0 };
        parse_gnu_attribute_string_arg(attribute, &string);
        if (string.begin != NULL) {
-               for(int i = 0; i < 3; ++i) {
+               for (int i = 0; i < 3; ++i) {
                        if (strcmp(visibilities[i], string.begin) == 0) {
                                attribute->u.value = i;
                                return;
@@ -1467,6 +1469,9 @@ static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute)
        attribute->invalid = true;
 }
 
+/**
+ * Parse one mode of the given attribute.
+ */
 static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
 {
        /* TODO: find out what is allowed here... */
@@ -1476,7 +1481,7 @@ static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
        add_anchor_token(')');
 
        if (token.type != T_IDENTIFIER) {
-               expect(T_IDENTIFIER);
+               expect(T_IDENTIFIER, end_error);
        }
 
        /* This isn't really correct, the backend should provide a list of machine
@@ -1501,14 +1506,14 @@ static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
        next_token();
 
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
        return;
 end_error:
        attribute->invalid = true;
 }
 
 /**
- * parse one interrupt argument.
+ * Parse one interrupt argument of the given attribute.
  */
 static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute)
 {
@@ -1522,7 +1527,7 @@ static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute)
        string_t string = { NULL, 0 };
        parse_gnu_attribute_string_arg(attribute, &string);
        if (string.begin != NULL) {
-               for(size_t i = 0; i < 5; ++i) {
+               for (size_t i = 0; i < 5; ++i) {
                        if (strcmp(interrupts[i], string.begin) == 0) {
                                attribute->u.value = i;
                                return;
@@ -1534,7 +1539,7 @@ static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute)
 }
 
 /**
- * parse ( identifier, const expression, const expression )
+ * Parse ( identifier, const expression, const expression )
  */
 static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
 {
@@ -1551,7 +1556,7 @@ static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
                goto end_error;
        }
        const char *name = token.v.symbol->string;
-       for(i = 0; i < 4; ++i) {
+       for (i = 0; i < 4; ++i) {
                if (strcmp_underscore(format_names[i], name) == 0)
                        break;
        }
@@ -1561,23 +1566,26 @@ static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
        }
        next_token();
 
-       expect(',');
+       expect(',', end_error);
        add_anchor_token(')');
        add_anchor_token(',');
        parse_constant_expression();
        rem_anchor_token(',');
        rem_anchor_token(')');
 
-       expect(',');
+       expect(',', end_error);
        add_anchor_token(')');
        parse_constant_expression();
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
        return;
 end_error:
        attribute->u.value = true;
 }
 
+/**
+ * Check that a given GNU attribute has no arguments.
+ */
 static void check_no_argument(gnu_attribute_t *attribute, const char *name)
 {
        if (!attribute->have_arguments)
@@ -1675,8 +1683,8 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes)
        gnu_attribute_t *attribute;
 
        eat(T___attribute__);
-       expect('(');
-       expect('(');
+       expect('(', end_error);
+       expect('(', end_error);
 
        if (token.type != ')') {
                /* find the end of the list */
@@ -1706,7 +1714,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes)
                        next_token();
 
                        int i;
-                       for(i = 0; i < GNU_AK_LAST; ++i) {
+                       for (i = 0; i < GNU_AK_LAST; ++i) {
                                if (strcmp_underscore(gnu_attribute_names[i], name) == 0)
                                        break;
                        }
@@ -1892,8 +1900,8 @@ no_arg:
                        next_token();
                }
        }
-       expect(')');
-       expect(')');
+       expect(')', end_error);
+       expect(')', end_error);
 end_error:
        *attributes = head;
 
@@ -1915,7 +1923,7 @@ static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes)
 
                case T_asm:
                        next_token();
-                       expect('(');
+                       expect('(', end_error);
                        if (token.type != T_STRING_LITERAL) {
                                parse_error_expected("while parsing assembler attribute",
                                                     T_STRING_LITERAL, NULL);
@@ -1924,7 +1932,7 @@ static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes)
                        } else {
                                parse_string_literals();
                        }
-                       expect(')');
+                       expect(')', end_error);
                        continue;
 
                case T_cdecl:     modifiers |= DM_CDECL;    break;
@@ -1945,39 +1953,40 @@ end_error:
        }
 }
 
-static void mark_vars_read(expression_t *expr, variable_t *lhs_var);
+static void mark_vars_read(expression_t *expr, entity_t *lhs_ent);
 
-static variable_t *determine_lhs_var(expression_t *const expr,
-                                     variable_t *lhs_var)
+static entity_t *determine_lhs_ent(expression_t *const expr,
+                                   entity_t *lhs_ent)
 {
        switch (expr->kind) {
                case EXPR_REFERENCE: {
                        entity_t *const entity = expr->reference.entity;
-                       /* we should only find variables as lavlues... */
-                       if (entity->base.kind != ENTITY_VARIABLE)
+                       /* we should only find variables as lvalues... */
+                       if (entity->base.kind != ENTITY_VARIABLE
+                                       && entity->base.kind != ENTITY_PARAMETER)
                                return NULL;
 
-                       return &entity->variable;
+                       return entity;
                }
 
                case EXPR_ARRAY_ACCESS: {
-                       expression_t  *const ref = expr->array_access.array_ref;
-                       variable_t    *      var = NULL;
+                       expression_t *const ref = expr->array_access.array_ref;
+                       entity_t     *      ent = NULL;
                        if (is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) {
-                               var     = determine_lhs_var(ref, lhs_var);
-                               lhs_var = var;
+                               ent     = determine_lhs_ent(ref, lhs_ent);
+                               lhs_ent = ent;
                        } else {
-                               mark_vars_read(expr->select.compound, lhs_var);
+                               mark_vars_read(expr->select.compound, lhs_ent);
                        }
-                       mark_vars_read(expr->array_access.index, lhs_var);
-                       return var;
+                       mark_vars_read(expr->array_access.index, lhs_ent);
+                       return ent;
                }
 
                case EXPR_SELECT: {
                        if (is_type_compound(skip_typeref(expr->base.type))) {
-                               return determine_lhs_var(expr->select.compound, lhs_var);
+                               return determine_lhs_ent(expr->select.compound, lhs_ent);
                        } else {
-                               mark_vars_read(expr->select.compound, lhs_var);
+                               mark_vars_read(expr->select.compound, lhs_ent);
                                return NULL;
                        }
                }
@@ -1986,7 +1995,7 @@ static variable_t *determine_lhs_var(expression_t *const expr,
                        expression_t *const val = expr->unary.value;
                        if (val->kind == EXPR_UNARY_TAKE_ADDRESS) {
                                /* *&x is a NOP */
-                               return determine_lhs_var(val->unary.value, lhs_var);
+                               return determine_lhs_ent(val->unary.value, lhs_ent);
                        } else {
                                mark_vars_read(val, NULL);
                                return NULL;
@@ -1999,10 +2008,10 @@ static variable_t *determine_lhs_var(expression_t *const expr,
        }
 }
 
-#define VAR_ANY ((variable_t*)-1)
+#define ENT_ANY ((entity_t*)-1)
 
 /**
- * Mark declarations, which are read.  This is used to deted variables, which
+ * Mark declarations, which are read.  This is used to detect variables, which
  * are never read.
  * Example:
  * x = x + 1;
@@ -2013,17 +2022,21 @@ static variable_t *determine_lhs_var(expression_t *const expr,
  *   x and y are not detected as "not read", because multiple variables are
  *   involved.
  */
-static void mark_vars_read(expression_t *const expr, variable_t *lhs_var)
+static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
 {
        switch (expr->kind) {
                case EXPR_REFERENCE: {
                        entity_t *const entity = expr->reference.entity;
-                       if (entity->kind != ENTITY_VARIABLE)
+                       if (entity->kind != ENTITY_VARIABLE
+                                       && entity->kind != ENTITY_PARAMETER)
                                return;
 
-                       variable_t *variable = &entity->variable;
-                       if (lhs_var != variable && lhs_var != VAR_ANY) {
-                               variable->read = true;
+                       if (lhs_ent != entity && lhs_ent != ENT_ANY) {
+                               if (entity->kind == ENTITY_VARIABLE) {
+                                       entity->variable.read = true;
+                               } else {
+                                       entity->parameter.read = true;
+                               }
                        }
                        return;
                }
@@ -2040,32 +2053,33 @@ static void mark_vars_read(expression_t *const expr, variable_t *lhs_var)
                        // TODO lhs_decl should depend on whether true/false have an effect
                        mark_vars_read(expr->conditional.condition, NULL);
                        if (expr->conditional.true_expression != NULL)
-                               mark_vars_read(expr->conditional.true_expression, lhs_var);
-                       mark_vars_read(expr->conditional.false_expression, lhs_var);
+                               mark_vars_read(expr->conditional.true_expression, lhs_ent);
+                       mark_vars_read(expr->conditional.false_expression, lhs_ent);
                        return;
 
                case EXPR_SELECT:
-                       if (lhs_var == VAR_ANY && !is_type_compound(skip_typeref(expr->base.type)))
-                               lhs_var = NULL;
-                       mark_vars_read(expr->select.compound, lhs_var);
+                       if (lhs_ent == ENT_ANY
+                                       && !is_type_compound(skip_typeref(expr->base.type)))
+                               lhs_ent = NULL;
+                       mark_vars_read(expr->select.compound, lhs_ent);
                        return;
 
                case EXPR_ARRAY_ACCESS: {
                        expression_t *const ref = expr->array_access.array_ref;
-                       mark_vars_read(ref, lhs_var);
-                       lhs_var = determine_lhs_var(ref, lhs_var);
-                       mark_vars_read(expr->array_access.index, lhs_var);
+                       mark_vars_read(ref, lhs_ent);
+                       lhs_ent = determine_lhs_ent(ref, lhs_ent);
+                       mark_vars_read(expr->array_access.index, lhs_ent);
                        return;
                }
 
                case EXPR_VA_ARG:
-                       mark_vars_read(expr->va_arge.ap, lhs_var);
+                       mark_vars_read(expr->va_arge.ap, lhs_ent);
                        return;
 
                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))
-                               lhs_var = NULL;
+                               lhs_ent = NULL;
                        goto unary;
 
 
@@ -2076,8 +2090,8 @@ static void mark_vars_read(expression_t *const expr, variable_t *lhs_var)
                case EXPR_UNARY_DEREFERENCE:
                case EXPR_UNARY_DELETE:
                case EXPR_UNARY_DELETE_ARRAY:
-                       if (lhs_var == VAR_ANY)
-                               lhs_var = NULL;
+                       if (lhs_ent == ENT_ANY)
+                               lhs_ent = NULL;
                        goto unary;
 
                case EXPR_UNARY_NEGATE:
@@ -2092,7 +2106,7 @@ static void mark_vars_read(expression_t *const expr, variable_t *lhs_var)
                case EXPR_UNARY_CAST_IMPLICIT:
                case EXPR_UNARY_ASSUME:
 unary:
-                       mark_vars_read(expr->unary.value, lhs_var);
+                       mark_vars_read(expr->unary.value, lhs_ent);
                        return;
 
                case EXPR_BINARY_ADD:
@@ -2120,8 +2134,8 @@ unary:
                case EXPR_BINARY_ISLESSEQUAL:
                case EXPR_BINARY_ISLESSGREATER:
                case EXPR_BINARY_ISUNORDERED:
-                       mark_vars_read(expr->binary.left,  lhs_var);
-                       mark_vars_read(expr->binary.right, lhs_var);
+                       mark_vars_read(expr->binary.left,  lhs_ent);
+                       mark_vars_read(expr->binary.right, lhs_ent);
                        return;
 
                case EXPR_BINARY_ASSIGN:
@@ -2135,15 +2149,15 @@ unary:
                case EXPR_BINARY_BITWISE_AND_ASSIGN:
                case EXPR_BINARY_BITWISE_XOR_ASSIGN:
                case EXPR_BINARY_BITWISE_OR_ASSIGN: {
-                       if (lhs_var == VAR_ANY)
-                               lhs_var = NULL;
-                       lhs_var = determine_lhs_var(expr->binary.left, lhs_var);
-                       mark_vars_read(expr->binary.right, lhs_var);
+                       if (lhs_ent == ENT_ANY)
+                               lhs_ent = NULL;
+                       lhs_ent = determine_lhs_ent(expr->binary.left, lhs_ent);
+                       mark_vars_read(expr->binary.right, lhs_ent);
                        return;
                }
 
                case EXPR_VA_START:
-                       determine_lhs_var(expr->va_starte.ap, lhs_var);
+                       determine_lhs_ent(expr->va_starte.ap, lhs_ent);
                        return;
 
                case EXPR_UNKNOWN:
@@ -2164,7 +2178,6 @@ unary:
                case EXPR_OFFSETOF:
                case EXPR_STATEMENT: // TODO
                case EXPR_LABEL_ADDRESS:
-               case EXPR_BINARY_BUILTIN_EXPECT:
                case EXPR_REFERENCE_ENUM_VALUE:
                        return;
        }
@@ -2187,7 +2200,7 @@ static designator_t *parse_designation(void)
                        add_anchor_token(']');
                        designator->array_index = parse_constant_expression();
                        rem_anchor_token(']');
-                       expect(']');
+                       expect(']', end_error);
                        break;
                case '.':
                        designator = allocate_ast_zero(sizeof(designator[0]));
@@ -2202,7 +2215,7 @@ static designator_t *parse_designation(void)
                        next_token();
                        break;
                default:
-                       expect('=');
+                       expect('=', end_error);
                        return result;
                }
 
@@ -2333,7 +2346,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
        mark_vars_read(expression, NULL);
        if (must_be_constant && !is_initializer_constant(expression)) {
                errorf(&expression->base.source_position,
-                      "Initialisation expression '%E' is not constant\n",
+                      "Initialisation expression '%E' is not constant",
                       expression);
        }
 
@@ -2395,7 +2408,7 @@ static __attribute__((unused)) void debug_print_type_path(
 {
        size_t len = ARR_LEN(path->path);
 
-       for(size_t i = 0; i < len; ++i) {
+       for (size_t i = 0; i < len; ++i) {
                const type_path_entry_t *entry = & path->path[i];
 
                type_t *type = skip_typeref(entry->type);
@@ -2408,7 +2421,7 @@ static __attribute__((unused)) void debug_print_type_path(
                        fprintf(stderr, ".%s",
                                entry->v.compound_entry->base.symbol->string);
                } else if (is_type_array(type)) {
-                       fprintf(stderr, "[%zu]", entry->v.index);
+                       fprintf(stderr, "[%u]", (unsigned) entry->v.index);
                } else {
                        fprintf(stderr, "-INVALID-");
                }
@@ -2505,7 +2518,7 @@ static void ascend_to(type_path_t *path, size_t top_path_level)
 static bool walk_designator(type_path_t *path, const designator_t *designator,
                             bool used_in_offsetof)
 {
-       for; designator != NULL; designator = designator->next) {
+       for (; designator != NULL; designator = designator->next) {
                type_path_entry_t *top       = get_type_path_top(path);
                type_t            *orig_type = top->type;
 
@@ -2526,7 +2539,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        } else {
                                compound_t *compound = type->compound.compound;
                                entity_t   *iter     = compound->members.entities;
-                               for; iter != NULL; iter = iter->base.next) {
+                               for (; iter != NULL; iter = iter->base.next) {
                                        if (iter->base.symbol == symbol) {
                                                break;
                                        }
@@ -2760,9 +2773,9 @@ finish_designator:
 
                                if (type != NULL) {
                                        ascend_from_subtype(path);
-                                       expect('}');
+                                       expect('}', end_error);
                                } else {
-                                       expect('}');
+                                       expect('}', end_error);
                                        goto error_parse_next;
                                }
                        }
@@ -2772,7 +2785,7 @@ finish_designator:
 
                        if (env->must_be_constant && !is_initializer_constant(expression)) {
                                errorf(&expression->base.source_position,
-                                      "Initialisation expression '%E' is not constant\n",
+                                      "Initialisation expression '%E' is not constant",
                                       expression);
                        }
 
@@ -2856,7 +2869,7 @@ error_parse_next:
                if (token.type == '}') {
                        break;
                }
-               expect(',');
+               expect(',', end_error);
                if (token.type == '}') {
                        break;
                }
@@ -2921,7 +2934,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                max_index = path.max_index;
                DEL_ARR_F(path.path);
 
-               expect('}');
+               expect('}', end_error);
        } else {
                /* parse_scalar_initializer() also works in this case: we simply
                 * have an expression without {} around it */
@@ -2995,7 +3008,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                eat(T_union);
        }
 
-       symbol_t   *symbol      = NULL;
+       symbol_t   *symbol   = NULL;
        compound_t *compound = NULL;
 
        if (token.type == T___attribute__) {
@@ -3006,13 +3019,13 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                symbol = token.v.symbol;
                next_token();
 
-               namespace_t const namespc =
+               namespace_tag_t const namespc =
                        is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION;
                entity_t *entity = get_entity(symbol, namespc);
                if (entity != NULL) {
                        assert(entity->kind == (is_struct ? ENTITY_STRUCT : ENTITY_UNION));
                        compound = &entity->compound;
-                       if (compound->base.parent_scope != scope &&
+                       if (compound->base.parent_scope != current_scope &&
                            (token.type == '{' || token.type == ';')) {
                                /* we're in an inner scope and have a definition. Override
                                   existing definition in outer scope */
@@ -3047,18 +3060,21 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                        (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
                compound->base.source_position = token.source_position;
                compound->base.symbol          = symbol;
-               compound->base.parent_scope    = scope;
+               compound->base.parent_scope    = current_scope;
                if (symbol != NULL) {
                        environment_push(entity);
                }
-               append_entity(scope, entity);
+               append_entity(current_scope, entity);
        }
 
        if (token.type == '{') {
-               compound->complete = true;
-
                parse_compound_type_entries(compound);
                modifiers |= parse_attributes(&attributes);
+
+               if (symbol == NULL) {
+                       assert(anonymous_entity == NULL);
+                       anonymous_entity = (entity_t*)compound;
+               }
        }
 
        compound->modifiers |= modifiers;
@@ -3070,8 +3086,8 @@ static void parse_enum_entries(type_t *const enum_type)
        eat('{');
 
        if (token.type == '}') {
-               next_token();
                errorf(HERE, "empty enum not allowed");
+               next_token();
                return;
        }
 
@@ -3108,7 +3124,7 @@ static void parse_enum_entries(type_t *const enum_type)
        } while (token.type != '}');
        rem_anchor_token('}');
 
-       expect('}');
+       expect('}', end_error);
 
 end_error:
        ;
@@ -3141,7 +3157,7 @@ static type_t *parse_enum_specifier(void)
                entity->base.namespc         = NAMESPACE_ENUM;
                entity->base.source_position = token.source_position;
                entity->base.symbol          = symbol;
-               entity->base.parent_scope    = scope;
+               entity->base.parent_scope    = current_scope;
        }
 
        type_t *const type = allocate_type_zero(TYPE_ENUM);
@@ -3149,19 +3165,24 @@ static type_t *parse_enum_specifier(void)
 
        if (token.type == '{') {
                if (entity->enume.complete) {
-                       errorf(HERE, "multiple definitions of enum %Y (previous definition %P)",
+                       errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
                               symbol, &entity->base.source_position);
                }
                if (symbol != NULL) {
                        environment_push(entity);
                }
-               append_entity(scope, entity);
+               append_entity(current_scope, entity);
                entity->enume.complete = true;
 
                parse_enum_entries(type);
                parse_attributes(&attributes);
-       } else if(!entity->enume.complete && !(c_mode & _GNUC)) {
-               errorf(HERE, "enum %Y used before definition (incomplete enumes are a GNU extension)",
+
+               if (symbol == NULL) {
+                       assert(anonymous_entity == NULL);
+                       anonymous_entity = entity;
+               }
+       } else if (!entity->enume.complete && !(c_mode & _GNUC)) {
+               errorf(HERE, "'enum %Y' used before definition (incomplete enums are a GNU extension)",
                       symbol);
        }
 
@@ -3183,7 +3204,7 @@ static type_t *parse_typeof(void)
 
        type_t *type;
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
 
        expression_t *expression  = NULL;
@@ -3220,7 +3241,7 @@ static type_t *parse_typeof(void)
        in_gcc_extension = old_gcc_extension;
 
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
        type_t *typeof_type              = allocate_type_zero(TYPE_TYPEOF);
        typeof_type->typeoft.expression  = expression;
@@ -3316,7 +3337,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                symbol_t *symbol = token.v.symbol;
                if (symbol == sym_align) {
                        next_token();
-                       expect('(');
+                       expect('(', end_error);
                        if (token.type != T_INTEGER)
                                goto end_error;
                        if (check_alignment_value(token.v.intvalue)) {
@@ -3325,14 +3346,14 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                                specifiers->alignment = (unsigned char)token.v.intvalue;
                        }
                        next_token();
-                       expect(')');
+                       expect(')', end_error);
                } else if (symbol == sym_allocate) {
                        next_token();
-                       expect('(');
+                       expect('(', end_error);
                        if (token.type != T_IDENTIFIER)
                                goto end_error;
                        (void)token.v.symbol;
-                       expect(')');
+                       expect(')', end_error);
                } else if (symbol == sym_dllimport) {
                        next_token();
                        DET_MOD(dllimport, DM_DLLIMPORT);
@@ -3359,7 +3380,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                        DET_MOD(novtable, DM_NOVTABLE);
                } else if (symbol == sym_property) {
                        next_token();
-                       expect('(');
+                       expect('(', end_error);
                        for (;;) {
                                bool is_get = false;
                                if (token.type != T_IDENTIFIER)
@@ -3372,7 +3393,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                                        goto end_error;
                                }
                                next_token();
-                               expect('=');
+                               expect('=', end_error);
                                if (token.type != T_IDENTIFIER)
                                        goto end_error;
                                if (is_get) {
@@ -3395,17 +3416,17 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                                }
                                break;
                        }
-                       expect(')');
+                       expect(')', end_error);
                } else if (symbol == sym_selectany) {
                        next_token();
                        DET_MOD(selectany, DM_SELECTANY);
                } else if (symbol == sym_uuid) {
                        next_token();
-                       expect('(');
+                       expect('(', end_error);
                        if (token.type != T_STRING_LITERAL)
                                goto end_error;
                        next_token();
-                       expect(')');
+                       expect(')', end_error);
                } else if (symbol == sym_deprecated) {
                        next_token();
                        if (specifiers->deprecated != 0 && warning.other)
@@ -3419,14 +3440,14 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                                } else {
                                        errorf(HERE, "string literal expected");
                                }
-                               expect(')');
+                               expect(')', end_error);
                        }
                } else if (symbol == sym_noalias) {
                        next_token();
                        DET_MOD(noalias, DM_NOALIAS);
                } else {
                        if (warning.other)
-                               warningf(HERE, "Unknown modifier %Y ignored", token.v.symbol);
+                               warningf(HERE, "Unknown modifier '%Y' ignored", token.v.symbol);
                        next_token();
                        if (token.type == '(')
                                skip_until(')');
@@ -3448,12 +3469,48 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
                entity->declaration.type     = type_error_type;
                entity->declaration.implicit = true;
        } else if (kind == ENTITY_TYPEDEF) {
-               entity->typedefe.type = type_error_type;
+               entity->typedefe.type    = type_error_type;
+               entity->typedefe.builtin = true;
        }
        record_entity(entity, false);
        return entity;
 }
 
+static void parse_microsoft_based(based_spec_t *based_spec)
+{
+       if (token.type != T_IDENTIFIER) {
+               parse_error_expected("while parsing __based", T_IDENTIFIER, NULL);
+               return;
+       }
+       symbol_t *symbol = token.v.symbol;
+       entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
+
+       if (entity == NULL || entity->base.kind != ENTITY_VARIABLE) {
+               errorf(HERE, "'%Y' is not a variable name.", symbol);
+               entity = create_error_entity(symbol, ENTITY_VARIABLE);
+       } else {
+               variable_t *variable = &entity->variable;
+
+               if (based_spec->base_variable != NULL) {
+                       errorf(HERE, "__based type qualifier specified more than once");
+               }
+               based_spec->source_position = token.source_position;
+               based_spec->base_variable   = variable;
+
+               type_t *const type = variable->base.type;
+
+               if (is_type_valid(type)) {
+                       if (! is_type_pointer(skip_typeref(type))) {
+                               errorf(HERE, "variable in __based modifier must have pointer type instead of '%T'", type);
+                       }
+                       if (variable->base.base.parent_scope != file_scope) {
+                               errorf(HERE, "a nonstatic local variable may not be used in a __based specification");
+                       }
+               }
+       }
+       next_token();
+}
+
 /**
  * Finish the construction of a struct type by calculating
  * its size, offsets, alignment.
@@ -3500,14 +3557,15 @@ static void finish_struct_type(compound_type_t *type)
        if (offset > size)
                need_pad = true;
 
-       if (warning.padded && need_pad) {
-               warningf(&compound->base.source_position,
-                       "'%#T' needs padding", type, compound->base.symbol);
-       }
-       if (warning.packed && !need_pad) {
-               warningf(&compound->base.source_position,
-                       "superfluous packed attribute on '%#T'",
-                       type, compound->base.symbol);
+       if (need_pad) {
+               if (warning.padded) {
+                       warningf(&compound->base.source_position, "'%T' needs padding", type);
+               }
+       } else {
+               if (compound->modifiers & DM_PACKED && warning.packed) {
+                       warningf(&compound->base.source_position,
+                                       "superfluous packed attribute on '%T'", type);
+               }
        }
 
        type->base.size      = offset;
@@ -3571,7 +3629,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
 
                switch (token.type) {
-
                /* storage class */
 #define MATCH_STORAGE_CLASS(token, class)                                  \
                case token:                                                        \
@@ -3579,6 +3636,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                                errorf(HERE, "multiple storage classes in declaration specifiers"); \
                        }                                                              \
                        specifiers->storage_class = class;                             \
+                       if (specifiers->thread_local)                                  \
+                               goto check_thread_storage_class;                           \
                        next_token();                                                  \
                        break;
 
@@ -3590,30 +3649,33 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 
                case T__declspec:
                        next_token();
-                       expect('(');
+                       expect('(', end_error);
                        add_anchor_token(')');
                        parse_microsoft_extended_decl_modifier(specifiers);
                        rem_anchor_token(')');
-                       expect(')');
+                       expect(')', end_error);
                        break;
 
                case T___thread:
-                       switch (specifiers->storage_class) {
-                       case STORAGE_CLASS_NONE:
-                               specifiers->storage_class = STORAGE_CLASS_THREAD;
-                               break;
-
-                       case STORAGE_CLASS_EXTERN:
-                               specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN;
-                               break;
-
-                       case STORAGE_CLASS_STATIC:
-                               specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC;
-                               break;
+                       if (specifiers->thread_local) {
+                               errorf(HERE, "duplicate '__thread'");
+                       } else {
+                               specifiers->thread_local = true;
+check_thread_storage_class:
+                               switch (specifiers->storage_class) {
+                                       case STORAGE_CLASS_EXTERN:
+                                       case STORAGE_CLASS_NONE:
+                                       case STORAGE_CLASS_STATIC:
+                                               break;
 
-                       default:
-                               errorf(HERE, "multiple storage classes in declaration specifiers");
-                               break;
+                                               char const* wrong;
+                                       case STORAGE_CLASS_AUTO:     wrong = "auto";     goto wrong_thread_stoarge_class;
+                                       case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class;
+                                       case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_stoarge_class;
+wrong_thread_stoarge_class:
+                                               errorf(HERE, "'__thread' used with '%s'", wrong);
+                                               break;
+                               }
                        }
                        next_token();
                        break;
@@ -3642,12 +3704,12 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                /* type specifiers */
 #define MATCH_SPECIFIER(token, specifier, name)                         \
                case token:                                                     \
-                       next_token();                                               \
                        if (type_specifiers & specifier) {                           \
                                errorf(HERE, "multiple " name " type specifiers given"); \
                        } else {                                                    \
                                type_specifiers |= specifier;                           \
                        }                                                           \
+                       next_token();                                               \
                        break
 
                MATCH_SPECIFIER(T__Bool,      SPECIFIER_BOOL,      "_Bool");
@@ -3679,7 +3741,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        break;
 
                case T_long:
-                       next_token();
                        if (type_specifiers & SPECIFIER_LONG_LONG) {
                                errorf(HERE, "multiple type specifiers given");
                        } else if (type_specifiers & SPECIFIER_LONG) {
@@ -3687,6 +3748,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        } else {
                                type_specifiers |= SPECIFIER_LONG;
                        }
+                       next_token();
                        break;
 
                case T_struct: {
@@ -3730,6 +3792,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                                        case T_inline:
                                        case T__forceinline: /* ^ DECLARATION_START except for __attribute__ */
                                        case T_IDENTIFIER:
+                                       case '&':
                                        case '*':
                                                errorf(HERE, "discarding stray %K in declaration specifier", &token);
                                                next_token();
@@ -3749,6 +3812,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                                switch (la1_type) {
                                        DECLARATION_START
                                        case T_IDENTIFIER:
+                                       case '&':
                                        case '*': {
                                                errorf(HERE, "%K does not name a type", &token);
 
@@ -3760,7 +3824,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 
                                                next_token();
                                                saw_error = true;
-                                               if (la1_type == '*')
+                                               if (la1_type == '&' || la1_type == '*')
                                                        goto finish_specifiers;
                                                continue;
                                        }
@@ -4008,7 +4072,7 @@ static type_qualifiers_t parse_type_qualifiers(void)
 static void parse_identifier_list(scope_t *scope)
 {
        do {
-               entity_t *entity = allocate_entity_zero(ENTITY_VARIABLE);
+               entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER);
                entity->base.source_position = token.source_position;
                entity->base.namespc         = NAMESPACE_NORMAL;
                entity->base.symbol          = token.v.symbol;
@@ -4024,40 +4088,6 @@ static void parse_identifier_list(scope_t *scope)
        } while (token.type == T_IDENTIFIER);
 }
 
-static type_t *automatic_type_conversion(type_t *orig_type);
-
-static void semantic_parameter(declaration_t *declaration)
-{
-       /* TODO: improve error messages */
-       source_position_t const* const pos = &declaration->base.source_position;
-
-       /* Â§6.9.1:6 */
-       switch (declaration->declared_storage_class) {
-               /* Allowed storage classes */
-               case STORAGE_CLASS_NONE:
-               case STORAGE_CLASS_REGISTER:
-                       break;
-
-               default:
-                       errorf(pos, "parameter may only have none or register storage class");
-                       break;
-       }
-
-       type_t *const orig_type = declaration->type;
-       /* Â§6.7.5.3(7): Array as last part of a parameter type is just syntactic
-        * sugar.  Turn it into a pointer.
-        * Â§6.7.5.3(8): A declaration of a parameter as ``function returning type''
-        * shall be adjusted to ``pointer to function returning type'', as in 6.3.2.1.
-        */
-       type_t *const type = automatic_type_conversion(orig_type);
-       declaration->type = type;
-
-       if (is_type_incomplete(skip_typeref(type))) {
-               errorf(pos, "parameter '%#T' is of incomplete type",
-                      orig_type, declaration->base.symbol);
-       }
-}
-
 static entity_t *parse_parameter(void)
 {
        declaration_specifiers_t specifiers;
@@ -4065,10 +4095,28 @@ static entity_t *parse_parameter(void)
 
        parse_declaration_specifiers(&specifiers);
 
-       entity_t *entity = parse_declarator(&specifiers, true, false);
+       entity_t *entity = parse_declarator(&specifiers,
+                       DECL_MAY_BE_ABSTRACT | DECL_IS_PARAMETER);
+       anonymous_entity = NULL;
        return entity;
 }
 
+static void semantic_parameter_incomplete(const entity_t *entity)
+{
+       assert(entity->kind == ENTITY_PARAMETER);
+
+       /* Â§6.7.5.3:4  After adjustment, the parameters in a parameter type
+        *             list in a function declarator that is part of a
+        *             definition of that function shall not have
+        *             incomplete type. */
+       type_t *type = skip_typeref(entity->declaration.type);
+       if (is_type_incomplete(type)) {
+               errorf(&entity->base.source_position,
+                      "parameter '%Y' has incomplete type '%T'", entity->base.symbol,
+                      entity->declaration.type);
+       }
+}
+
 /**
  * Parses function type parameters (and optionally creates variable_t entities
  * for them in a scope)
@@ -4125,7 +4173,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                                        && skip_typeref(entity->declaration.type) == type_void) {
                                goto parameters_finished;
                        }
-                       semantic_parameter(&entity->declaration);
+                       semantic_parameter_incomplete(entity);
 
                        parameter = obstack_alloc(type_obst, sizeof(parameter[0]));
                        memset(parameter, 0, sizeof(parameter[0]));
@@ -4156,7 +4204,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
 
 parameters_finished:
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
 end_error:
        restore_anchor_state(',', saved_comma_state);
@@ -4165,6 +4213,7 @@ end_error:
 typedef enum construct_type_kind_t {
        CONSTRUCT_INVALID,
        CONSTRUCT_POINTER,
+       CONSTRUCT_REFERENCE,
        CONSTRUCT_FUNCTION,
        CONSTRUCT_ARRAY
 } construct_type_kind_t;
@@ -4179,6 +4228,12 @@ typedef struct parsed_pointer_t parsed_pointer_t;
 struct parsed_pointer_t {
        construct_type_t  construct_type;
        type_qualifiers_t type_qualifiers;
+       variable_t        *base_variable;  /**< MS __based extension. */
+};
+
+typedef struct parsed_reference_t parsed_reference_t;
+struct parsed_reference_t {
+       construct_type_t construct_type;
 };
 
 typedef struct construct_function_type_t construct_function_type_t;
@@ -4202,7 +4257,7 @@ struct construct_base_type_t {
        type_t           *type;
 };
 
-static construct_type_t *parse_pointer_declarator(void)
+static construct_type_t *parse_pointer_declarator(variable_t *base_variable)
 {
        eat('*');
 
@@ -4210,8 +4265,20 @@ static construct_type_t *parse_pointer_declarator(void)
        memset(pointer, 0, sizeof(pointer[0]));
        pointer->construct_type.kind = CONSTRUCT_POINTER;
        pointer->type_qualifiers     = parse_type_qualifiers();
+       pointer->base_variable       = base_variable;
+
+       return &pointer->construct_type;
+}
+
+static construct_type_t *parse_reference_declarator(void)
+{
+       eat('&');
+
+       parsed_reference_t *reference = obstack_alloc(&temp_obst, sizeof(reference[0]));
+       memset(reference, 0, sizeof(reference[0]));
+       reference->construct_type.kind = CONSTRUCT_REFERENCE;
 
-       return (construct_type_t*) pointer;
+       return (construct_type_t*)reference;
 }
 
 static construct_type_t *parse_array_declarator(void)
@@ -4245,57 +4312,33 @@ static construct_type_t *parse_array_declarator(void)
        }
 
        rem_anchor_token(']');
-       expect(']');
+       expect(']', end_error);
 
 end_error:
-       return (construct_type_t*) array;
+       return &array->construct_type;
 }
 
-static construct_type_t *parse_function_declarator(scope_t *scope)
+static construct_type_t *parse_function_declarator(scope_t *scope,
+                                                   decl_modifiers_t modifiers)
 {
-       type_t *type = allocate_type_zero(TYPE_FUNCTION);
+       type_t          *type  = allocate_type_zero(TYPE_FUNCTION);
+       function_type_t *ftype = &type->function;
 
-       /* TODO: revive this... once we know exactly how to do it */
-#if 0
-       decl_modifiers_t  modifiers = entity->declaration.modifiers;
-
-       unsigned mask = modifiers & (DM_CDECL|DM_STDCALL|DM_FASTCALL|DM_THISCALL);
+       ftype->linkage = current_linkage;
 
-       if (mask & (mask-1)) {
-               const char *first = NULL, *second = NULL;
+       switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) {
+               case DM_NONE:     break;
+               case DM_CDECL:    ftype->calling_convention = CC_CDECL;    break;
+               case DM_STDCALL:  ftype->calling_convention = CC_STDCALL;  break;
+               case DM_FASTCALL: ftype->calling_convention = CC_FASTCALL; break;
+               case DM_THISCALL: ftype->calling_convention = CC_THISCALL; break;
 
-               /* more than one calling convention set */
-               if (modifiers & DM_CDECL) {
-                       if (first == NULL)       first = "cdecl";
-                       else if (second == NULL) second = "cdecl";
-               }
-               if (modifiers & DM_STDCALL) {
-                       if (first == NULL)       first = "stdcall";
-                       else if (second == NULL) second = "stdcall";
-               }
-               if (modifiers & DM_FASTCALL) {
-                       if (first == NULL)       first = "fastcall";
-                       else if (second == NULL) second = "fastcall";
-               }
-               if (modifiers & DM_THISCALL) {
-                       if (first == NULL)       first = "thiscall";
-                       else if (second == NULL) second = "thiscall";
-               }
-               errorf(&entity->base.source_position,
-                          "%s and %s attributes are not compatible", first, second);
+               default:
+                       errorf(HERE, "multiple calling conventions in declaration");
+                       break;
        }
 
-       if (modifiers & DM_CDECL)
-               type->function.calling_convention = CC_CDECL;
-       else if (modifiers & DM_STDCALL)
-               type->function.calling_convention = CC_STDCALL;
-       else if (modifiers & DM_FASTCALL)
-               type->function.calling_convention = CC_FASTCALL;
-       else if (modifiers & DM_THISCALL)
-               type->function.calling_convention = CC_THISCALL;
-#endif
-
-       parse_parameters(&type->function, scope);
+       parse_parameters(ftype, scope);
 
        construct_function_type_t *construct_function_type =
                obstack_alloc(&temp_obst, sizeof(construct_function_type[0]));
@@ -4324,9 +4367,43 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
 
        decl_modifiers_t modifiers = parse_attributes(&attributes);
 
-       /* pointers */
-       while (token.type == '*') {
-               construct_type_t *type = parse_pointer_declarator();
+       /* MS __based extension */
+       based_spec_t base_spec;
+       base_spec.base_variable = NULL;
+
+       for (;;) {
+               construct_type_t *type;
+               switch (token.type) {
+                       case '&':
+                               if (!(c_mode & _CXX))
+                                       errorf(HERE, "references are only available for C++");
+                               if (base_spec.base_variable != NULL && warning.other) {
+                                       warningf(&base_spec.source_position,
+                                                "__based does not precede a pointer operator, ignored");
+                               }
+                               type = parse_reference_declarator();
+                               /* consumed */
+                               base_spec.base_variable = NULL;
+                               break;
+
+                       case '*':
+                               type = parse_pointer_declarator(base_spec.base_variable);
+                               /* consumed */
+                               base_spec.base_variable = NULL;
+                               break;
+
+                       case T__based:
+                               next_token();
+                               expect('(', end_error);
+                               add_anchor_token(')');
+                               parse_microsoft_based(&base_spec);
+                               rem_anchor_token(')');
+                               expect(')', end_error);
+                               continue;
+
+                       default:
+                               goto ptr_operator_end;
+               }
 
                if (last == NULL) {
                        first = type;
@@ -4339,9 +4416,16 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
                /* TODO: find out if this is correct */
                modifiers |= parse_attributes(&attributes);
        }
+ptr_operator_end:
+       if (base_spec.base_variable != NULL && warning.other) {
+               warningf(&base_spec.source_position,
+                        "__based does not precede a pointer operator, ignored");
+       }
 
-       if (env != NULL)
-               env->modifiers |= modifiers;
+       if (env != NULL) {
+               modifiers      |= env->modifiers;
+               env->modifiers  = modifiers;
+       }
 
        construct_type_t *inner_types = NULL;
 
@@ -4356,15 +4440,20 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
                next_token();
                break;
        case '(':
-               next_token();
-               add_anchor_token(')');
-               inner_types = parse_inner_declarator(env, may_be_abstract);
-               if (inner_types != NULL) {
-                       /* All later declarators only modify the return type */
-                       env = NULL;
+               /* Â§6.7.6:2 footnote 126:  Empty parentheses in a type name are
+                * interpreted as ``function with no parameter specification'', rather
+                * than redundant parentheses around the omitted identifier. */
+               if (look_ahead(1)->type != ')') {
+                       next_token();
+                       add_anchor_token(')');
+                       inner_types = parse_inner_declarator(env, may_be_abstract);
+                       if (inner_types != NULL) {
+                               /* All later declarators only modify the return type */
+                               env = NULL;
+                       }
+                       rem_anchor_token(')');
+                       expect(')', end_error);
                }
-               rem_anchor_token(')');
-               expect(')');
                break;
        default:
                if (may_be_abstract)
@@ -4376,7 +4465,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
 
        construct_type_t *p = last;
 
-       while(true) {
+       while (true) {
                construct_type_t *type;
                switch (token.type) {
                case '(': {
@@ -4384,7 +4473,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
                        if (env != NULL)
                                scope = &env->parameters;
 
-                       type = parse_function_declarator(scope);
+                       type = parse_function_declarator(scope, modifiers);
                        break;
                }
                case '[':
@@ -4474,7 +4563,7 @@ static void parse_declaration_attributes(entity_t *entity)
 
        type_modifiers_t type_modifiers = type->base.modifiers;
        if (modifiers & DM_TRANSPARENT_UNION)
-               modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
+               type_modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
 
        if (type->base.modifiers != type_modifiers) {
                type_t *copy = duplicate_type(type);
@@ -4495,11 +4584,10 @@ static void parse_declaration_attributes(entity_t *entity)
        }
 }
 
-static type_t *construct_declarator_type(construct_type_t *construct_list,
-                                         type_t *type)
+static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
 {
        construct_type_t *iter = construct_list;
-       for; iter != NULL; iter = iter->next) {
+       for (; iter != NULL; iter = iter->next) {
                switch (iter->kind) {
                case CONSTRUCT_INVALID:
                        internal_errorf(HERE, "invalid type construction found");
@@ -4529,12 +4617,25 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                }
 
                case CONSTRUCT_POINTER: {
+                       if (is_type_reference(skip_typeref(type)))
+                               errorf(HERE, "cannot declare a pointer to reference");
+
                        parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
-                       type = make_pointer_type(type, parsed_pointer->type_qualifiers);
+                       type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, parsed_pointer->base_variable);
                        continue;
                }
 
+               case CONSTRUCT_REFERENCE:
+                       if (is_type_reference(skip_typeref(type)))
+                               errorf(HERE, "cannot declare a reference to reference");
+
+                       type = make_reference_type(type);
+                       continue;
+
                case CONSTRUCT_ARRAY: {
+                       if (is_type_reference(skip_typeref(type)))
+                               errorf(HERE, "cannot declare an array of references");
+
                        parsed_array_t *parsed_array  = (parsed_array_t*) iter;
                        type_t         *array_type    = allocate_type_zero(TYPE_ARRAY);
 
@@ -4586,16 +4687,53 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
        return type;
 }
 
+static type_t *automatic_type_conversion(type_t *orig_type);
+
+static type_t *semantic_parameter(const source_position_t *pos,
+                                  type_t *type,
+                                  const declaration_specifiers_t *specifiers,
+                                  symbol_t *symbol)
+{
+       /* Â§6.7.5.3:7  A declaration of a parameter as ``array of type''
+        *             shall be adjusted to ``qualified pointer to type'',
+        *             [...]
+        * Â§6.7.5.3:8  A declaration of a parameter as ``function returning
+        *             type'' shall be adjusted to ``pointer to function
+        *             returning type'', as in 6.3.2.1. */
+       type = automatic_type_conversion(type);
+
+       if (specifiers->is_inline && is_type_valid(type)) {
+               errorf(pos, "parameter '%Y' declared 'inline'", symbol);
+       }
+
+       /* Â§6.9.1:6  The declarations in the declaration list shall contain
+        *           no storage-class specifier other than register and no
+        *           initializations. */
+       if (specifiers->thread_local || (
+                       specifiers->storage_class != STORAGE_CLASS_NONE   &&
+                       specifiers->storage_class != STORAGE_CLASS_REGISTER)
+          ) {
+               errorf(pos, "invalid storage class for parameter '%Y'", symbol);
+       }
+
+       /* delay test for incomplete type, because we might have (void)
+        * which is legal but incomplete... */
+
+       return type;
+}
+
 static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
-                                  bool may_be_abstract,
-                                  bool create_compound_member)
+                                  declarator_flags_t flags)
 {
        parse_declarator_env_t env;
        memset(&env, 0, sizeof(env));
+       env.modifiers = specifiers->modifiers;
 
-       construct_type_t *construct_type
-               = parse_inner_declarator(&env, may_be_abstract);
-       type_t *type = construct_declarator_type(construct_type, specifiers->type);
+       construct_type_t *construct_type =
+               parse_inner_declarator(&env, (flags & DECL_MAY_BE_ABSTRACT) != 0);
+       type_t           *orig_type      =
+               construct_declarator_type(construct_type, specifiers->type);
+       type_t           *type           = skip_typeref(orig_type);
 
        if (construct_type != NULL) {
                obstack_free(&temp_obst, construct_type);
@@ -4606,15 +4744,57 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                entity                       = allocate_entity_zero(ENTITY_TYPEDEF);
                entity->base.symbol          = env.symbol;
                entity->base.source_position = env.source_position;
-               entity->typedefe.type        = type;
+               entity->typedefe.type        = orig_type;
+
+               if (anonymous_entity != NULL) {
+                       if (is_type_compound(type)) {
+                               assert(anonymous_entity->compound.alias == NULL);
+                               assert(anonymous_entity->kind == ENTITY_STRUCT ||
+                                      anonymous_entity->kind == ENTITY_UNION);
+                               anonymous_entity->compound.alias = entity;
+                               anonymous_entity = NULL;
+                       } else if (is_type_enum(type)) {
+                               assert(anonymous_entity->enume.alias == NULL);
+                               assert(anonymous_entity->kind == ENTITY_ENUM);
+                               anonymous_entity->enume.alias = entity;
+                               anonymous_entity = NULL;
+                       }
+               }
        } else {
-               if (create_compound_member) {
+               /* create a declaration type entity */
+               if (flags & DECL_CREATE_COMPOUND_MEMBER) {
                        entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
-               } else if (is_type_function(skip_typeref(type))) {
+
+                       if (specifiers->is_inline && is_type_valid(type)) {
+                               errorf(&env.source_position,
+                                               "compound member '%Y' declared 'inline'", env.symbol);
+                       }
+
+                       if (specifiers->thread_local ||
+                               specifiers->storage_class != STORAGE_CLASS_NONE) {
+                               errorf(&env.source_position,
+                                          "compound member '%Y' must have no storage class",
+                                          env.symbol);
+                       }
+               } else if (flags & DECL_IS_PARAMETER) {
+                       orig_type = semantic_parameter(&env.source_position, orig_type,
+                                                      specifiers, env.symbol);
+
+                       entity = allocate_entity_zero(ENTITY_PARAMETER);
+               } else if (is_type_function(type)) {
                        entity = allocate_entity_zero(ENTITY_FUNCTION);
 
                        entity->function.is_inline  = specifiers->is_inline;
                        entity->function.parameters = env.parameters;
+
+                       if (specifiers->thread_local || (
+                                       specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+                                       specifiers->storage_class != STORAGE_CLASS_NONE   &&
+                                       specifiers->storage_class != STORAGE_CLASS_STATIC)
+                          ) {
+                               errorf(&env.source_position,
+                                          "invalid storage class for function '%Y'", env.symbol);
+                       }
                } else {
                        entity = allocate_entity_zero(ENTITY_VARIABLE);
 
@@ -4625,25 +4805,44 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                entity->variable.alignment = specifiers->alignment;
                        }
 
-                       if (warning.other && specifiers->is_inline && is_type_valid(type)) {
-                               warningf(&env.source_position,
-                                                "variable '%Y' declared 'inline'\n", env.symbol);
+                       if (specifiers->is_inline && is_type_valid(type)) {
+                               errorf(&env.source_position,
+                                          "variable '%Y' declared 'inline'", env.symbol);
+                       }
+
+                       entity->variable.thread_local = specifiers->thread_local;
+
+                       bool invalid_storage_class = false;
+                       if (current_scope == file_scope) {
+                               if (specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+                                               specifiers->storage_class != STORAGE_CLASS_NONE   &&
+                                               specifiers->storage_class != STORAGE_CLASS_STATIC) {
+                                       invalid_storage_class = true;
+                               }
+                       } else {
+                               if (specifiers->thread_local &&
+                                               specifiers->storage_class == STORAGE_CLASS_NONE) {
+                                       invalid_storage_class = true;
+                               }
+                       }
+                       if (invalid_storage_class) {
+                               errorf(&env.source_position,
+                                               "invalid storage class for variable '%Y'", env.symbol);
                        }
                }
 
-               entity->base.source_position  = env.source_position;
-               entity->base.symbol           = env.symbol;
-               entity->base.namespc          = NAMESPACE_NORMAL;
-               entity->declaration.type      type;
-               entity->declaration.modifiers = env.modifiers | specifiers->modifiers;
+               entity->base.source_position          = env.source_position;
+               entity->base.symbol                   = env.symbol;
+               entity->base.namespc                  = NAMESPACE_NORMAL;
+               entity->declaration.type              = orig_type;
+               entity->declaration.modifiers         = env.modifiers;
                entity->declaration.deprecated_string = specifiers->deprecated_string;
 
                storage_class_t storage_class = specifiers->storage_class;
                entity->declaration.declared_storage_class = storage_class;
 
-               if (storage_class == STORAGE_CLASS_NONE && scope != file_scope) {
+               if (storage_class == STORAGE_CLASS_NONE && current_scope != file_scope)
                        storage_class = STORAGE_CLASS_AUTO;
-               }
                entity->declaration.storage_class = storage_class;
        }
 
@@ -4733,6 +4932,14 @@ 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)
+{
+       errorf(pos, "redeclaration of %s '%Y' as %s (declared %P)",
+              get_entity_kind_name(old->kind), old->base.symbol,
+              get_entity_kind_name(new_kind), &old->base.source_position);
+}
+
 /**
  * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
  * for various problems that occur for multiple definitions
@@ -4740,10 +4947,13 @@ static bool is_sym_main(const symbol_t *const sym)
 static entity_t *record_entity(entity_t *entity, const bool is_definition)
 {
        const symbol_t *const    symbol  = entity->base.symbol;
-       const namespace_t        namespc = entity->base.namespc;
+       const namespace_tag_t    namespc = (namespace_tag_t)entity->base.namespc;
        const source_position_t *pos     = &entity->base.source_position;
 
-       assert(symbol != NULL);
+       /* can happen in error cases */
+       if (symbol == NULL)
+               return entity;
+
        entity_t *previous_entity = get_entity(symbol, namespc);
        /* pushing the same entity twice will break the stack structure */
        assert(previous_entity != entity);
@@ -4760,52 +4970,47 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
                                         orig_type, symbol);
                }
 
-               if (warning.main && scope == file_scope && is_sym_main(symbol)) {
+               if (warning.main && current_scope == file_scope
+                               && is_sym_main(symbol)) {
                        check_type_of_main(entity);
                }
        }
 
-       if (is_declaration(entity)) {
-               if (warning.nested_externs
-                               && entity->declaration.storage_class == STORAGE_CLASS_EXTERN
-                               && scope != file_scope) {
-                       warningf(pos, "nested extern declaration of '%#T'",
-                                entity->declaration.type, symbol);
-               }
+       if (is_declaration(entity) &&
+                       warning.nested_externs &&
+                       entity->declaration.storage_class == STORAGE_CLASS_EXTERN &&
+                       current_scope != file_scope) {
+               warningf(pos, "nested extern declaration of '%#T'",
+                        entity->declaration.type, symbol);
        }
 
-       if (previous_entity != NULL
-           && previous_entity->base.parent_scope == &current_function->parameters
-               && scope->depth == previous_entity->base.parent_scope->depth + 1) {
-
-               assert(previous_entity->kind == ENTITY_VARIABLE);
+       if (previous_entity != NULL &&
+                       previous_entity->base.parent_scope == &current_function->parameters &&
+                       previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
+               assert(previous_entity->kind == ENTITY_PARAMETER);
                errorf(pos,
                       "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
-                      entity->declaration.type, symbol,
-                          previous_entity->declaration.type, symbol,
-                          &previous_entity->base.source_position);
+                                        entity->declaration.type, symbol,
+                                        previous_entity->declaration.type, symbol,
+                                        &previous_entity->base.source_position);
                goto finish;
        }
 
-       if (previous_entity != NULL
-                       && previous_entity->base.parent_scope == scope) {
-
+       if (previous_entity != NULL &&
+                       previous_entity->base.parent_scope == current_scope) {
                if (previous_entity->kind != entity->kind) {
-                       errorf(pos,
-                              "redeclaration of '%Y' as different kind of symbol (declared %P)",
-                              symbol, &previous_entity->base.source_position);
+                       error_redefined_as_different_kind(pos, previous_entity,
+                                                         entity->kind);
                        goto finish;
                }
                if (previous_entity->kind == ENTITY_ENUM_VALUE) {
-                       errorf(pos,
-                                  "redeclaration of enum entry '%Y' (declared %P)",
+                       errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
                                   symbol, &previous_entity->base.source_position);
                        goto finish;
                }
                if (previous_entity->kind == ENTITY_TYPEDEF) {
                        /* TODO: C++ allows this for exactly the same type */
-                       errorf(pos,
-                              "redefinition of typedef '%Y' (declared %P)",
+                       errorf(pos, "redefinition of typedef '%Y' (declared %P)",
                               symbol, &previous_entity->base.source_position);
                        goto finish;
                }
@@ -4813,50 +5018,47 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
                /* at this point we should have only VARIABLES or FUNCTIONS */
                assert(is_declaration(previous_entity) && is_declaration(entity));
 
+               declaration_t *const prev_decl = &previous_entity->declaration;
+               declaration_t *const decl      = &entity->declaration;
+
                /* can happen for K&R style declarations */
-               if (previous_entity->kind == ENTITY_VARIABLE
-                               && previous_entity->declaration.type == NULL
-                               && entity->kind == ENTITY_VARIABLE) {
-                       previous_entity->declaration.type = entity->declaration.type;
-                       previous_entity->declaration.storage_class
-                               = entity->declaration.storage_class;
-                       previous_entity->declaration.declared_storage_class
-                               = entity->declaration.declared_storage_class;
-                       previous_entity->declaration.modifiers
-                               = entity->declaration.modifiers;
-                       previous_entity->declaration.deprecated_string
-                               = entity->declaration.deprecated_string;
-               }
-               assert(entity->declaration.type != NULL);
-
-               declaration_t *const previous_declaration
-                       = &previous_entity->declaration;
-               declaration_t *const declaration = &entity->declaration;
-               type_t *const orig_type = entity->declaration.type;
+               if (prev_decl->type       == NULL             &&
+                               previous_entity->kind == ENTITY_PARAMETER &&
+                               entity->kind          == ENTITY_PARAMETER) {
+                       prev_decl->type                   = decl->type;
+                       prev_decl->storage_class          = decl->storage_class;
+                       prev_decl->declared_storage_class = decl->declared_storage_class;
+                       prev_decl->modifiers              = decl->modifiers;
+                       prev_decl->deprecated_string      = decl->deprecated_string;
+                       return previous_entity;
+               }
+
+               type_t *const orig_type = decl->type;
+               assert(orig_type != NULL);
                type_t *const type      = skip_typeref(orig_type);
-
-               type_t *prev_type       = skip_typeref(previous_declaration->type);
+               type_t *      prev_type = skip_typeref(prev_decl->type);
 
                if (!types_compatible(type, prev_type)) {
                        errorf(pos,
                                   "declaration '%#T' is incompatible with '%#T' (declared %P)",
-                                  orig_type, symbol, previous_declaration->type, symbol,
+                                  orig_type, symbol, prev_decl->type, symbol,
                                   &previous_entity->base.source_position);
                } else {
-                       unsigned old_storage_class = previous_declaration->storage_class;
-                       if (warning.redundant_decls     && is_definition
-                               && previous_declaration->storage_class == STORAGE_CLASS_STATIC
-                               && !(previous_declaration->modifiers & DM_USED)
-                               && !previous_declaration->used) {
+                       unsigned old_storage_class = prev_decl->storage_class;
+                       if (warning.redundant_decls               &&
+                                       is_definition                     &&
+                                       !prev_decl->used                  &&
+                                       !(prev_decl->modifiers & DM_USED) &&
+                                       prev_decl->storage_class == STORAGE_CLASS_STATIC) {
                                warningf(&previous_entity->base.source_position,
                                         "unnecessary static forward declaration for '%#T'",
-                                        previous_declaration->type, symbol);
+                                        prev_decl->type, symbol);
                        }
 
-                       unsigned new_storage_class = declaration->storage_class;
+                       unsigned new_storage_class = decl->storage_class;
                        if (is_type_incomplete(prev_type)) {
-                               previous_declaration->type = type;
-                               prev_type                  = type;
+                               prev_decl->type = type;
+                               prev_type       = type;
                        }
 
                        /* pretend no storage class means extern for function
@@ -4864,8 +5066,8 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
                         * none nor extern) */
                        if (entity->kind == ENTITY_FUNCTION) {
                                if (prev_type->function.unspecified_parameters) {
-                                       previous_declaration->type = type;
-                                       prev_type                  = type;
+                                       prev_decl->type = type;
+                                       prev_type       = type;
                                }
 
                                switch (old_storage_class) {
@@ -4897,7 +5099,8 @@ warn_redundant_declaration:
                                if (!is_definition           &&
                                    warning.redundant_decls  &&
                                    is_type_valid(prev_type) &&
-                                   strcmp(previous_entity->base.source_position.input_name, "<builtin>") != 0) {
+                                   strcmp(previous_entity->base.source_position.input_name,
+                                          "<builtin>") != 0) {
                                        warningf(pos,
                                                 "redundant declaration for '%Y' (declared %P)",
                                                 symbol, &previous_entity->base.source_position);
@@ -4909,8 +5112,8 @@ warn_redundant_declaration:
                                               "static declaration of '%Y' follows non-static declaration (declared %P)",
                                               symbol, &previous_entity->base.source_position);
                                } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
-                                       previous_declaration->storage_class          = STORAGE_CLASS_NONE;
-                                       previous_declaration->declared_storage_class = STORAGE_CLASS_NONE;
+                                       prev_decl->storage_class          = STORAGE_CLASS_NONE;
+                                       prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
                                } else {
                                        /* ISO/IEC 14882:1998(E) Â§C.1.2:1 */
                                        if (c_mode & _CXX)
@@ -4930,7 +5133,7 @@ error_redeclaration:
                        }
                }
 
-               previous_declaration->modifiers |= declaration->modifiers;
+               prev_decl->modifiers |= decl->modifiers;
                if (entity->kind == ENTITY_FUNCTION) {
                        previous_entity->function.is_inline |= entity->function.is_inline;
                }
@@ -4948,12 +5151,11 @@ error_redeclaration:
                                         entity->declaration.type, symbol);
                        }
                }
-       } else if (warning.missing_declarations
-                       && entity->kind == ENTITY_VARIABLE
-                       && scope == file_scope) {
+       } else if (warning.missing_declarations &&
+                       entity->kind == ENTITY_VARIABLE &&
+                       current_scope == file_scope) {
                declaration_t *declaration = &entity->declaration;
-               if (declaration->storage_class == STORAGE_CLASS_NONE ||
-                               declaration->storage_class == STORAGE_CLASS_THREAD) {
+               if (declaration->storage_class == STORAGE_CLASS_NONE) {
                        warningf(pos, "no previous declaration for '%#T'",
                                 declaration->type, symbol);
                }
@@ -4961,12 +5163,12 @@ error_redeclaration:
 
 finish:
        assert(entity->base.parent_scope == NULL);
-       assert(scope != NULL);
+       assert(current_scope != NULL);
 
-       entity->base.parent_scope = scope;
+       entity->base.parent_scope = current_scope;
        entity->base.namespc      = NAMESPACE_NORMAL;
        environment_push(entity);
-       append_entity(scope, entity);
+       append_entity(current_scope, entity);
 
        return entity;
 }
@@ -4974,7 +5176,7 @@ finish:
 static void parser_error_multiple_definition(entity_t *entity,
                const source_position_t *source_position)
 {
-       errorf(source_position, "multiple definition of symbol '%Y' (declared %P)",
+       errorf(source_position, "multiple definition of '%Y' (declared %P)",
               entity->base.symbol, &entity->base.source_position);
 }
 
@@ -5013,8 +5215,7 @@ static void parse_init_declarator_rest(entity_t *entity)
        }
 
        bool must_be_constant = false;
-       if (declaration->storage_class == STORAGE_CLASS_STATIC        ||
-           declaration->storage_class == STORAGE_CLASS_THREAD_STATIC ||
+       if (declaration->storage_class == STORAGE_CLASS_STATIC ||
            entity->base.parent_scope  == file_scope) {
                must_be_constant = true;
        }
@@ -5048,9 +5249,11 @@ static void parse_anonymous_declaration_rest(
                const declaration_specifiers_t *specifiers)
 {
        eat(';');
+       anonymous_entity = NULL;
 
        if (warning.other) {
-               if (specifiers->storage_class != STORAGE_CLASS_NONE) {
+               if (specifiers->storage_class != STORAGE_CLASS_NONE ||
+                               specifiers->thread_local) {
                        warningf(&specifiers->source_position,
                                 "useless storage class in empty declaration");
                }
@@ -5076,30 +5279,76 @@ static void parse_anonymous_declaration_rest(
        }
 }
 
-static void parse_declaration_rest(entity_t *ndeclaration,
-               const declaration_specifiers_t *specifiers,
-               parsed_declaration_func finished_declaration)
+static void check_variable_type_complete(entity_t *ent)
 {
-       add_anchor_token(';');
-       add_anchor_token(',');
-       while(true) {
-               entity_t *entity = finished_declaration(ndeclaration, token.type == '=');
+       if (ent->kind != ENTITY_VARIABLE)
+               return;
 
-               if (token.type == '=') {
+       /* Â§6.7:7  If an identifier for an object is declared with no linkage, the
+        *         type for the object shall be complete [...] */
+       declaration_t *decl = &ent->declaration;
+       if (decl->storage_class != STORAGE_CLASS_NONE)
+               return;
+
+       type_t *const orig_type = decl->type;
+       type_t *const type      = skip_typeref(orig_type);
+       if (!is_type_incomplete(type))
+               return;
+
+       /* GCC allows global arrays without size and assigns them a length of one,
+        * if no different declaration follows */
+       if (is_type_array(type) &&
+                       c_mode & _GNUC      &&
+                       ent->base.parent_scope == file_scope) {
+               ARR_APP1(declaration_t*, incomplete_arrays, decl);
+               return;
+       }
+
+       errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
+                       orig_type, ent->base.symbol);
+}
+
+
+static void parse_declaration_rest(entity_t *ndeclaration,
+               const declaration_specifiers_t *specifiers,
+               parsed_declaration_func         finished_declaration,
+               declarator_flags_t              flags)
+{
+       add_anchor_token(';');
+       add_anchor_token(',');
+       while (true) {
+               entity_t *entity = finished_declaration(ndeclaration, token.type == '=');
+
+               if (token.type == '=') {
                        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))) {
+                                       errorf(&entity->base.source_position,
+                                                       "reference '%#T' must be initialized",
+                                                       type, entity->base.symbol);
+                               }
+                       }
                }
 
+               check_variable_type_complete(entity);
+
                if (token.type != ',')
                        break;
                eat(',');
 
                add_anchor_token('=');
-               ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false, false);
+               ndeclaration = parse_declarator(specifiers, flags);
                rem_anchor_token('=');
        }
-       expect(';');
+       expect(';', end_error);
 
 end_error:
+       anonymous_entity = NULL;
        rem_anchor_token(';');
        rem_anchor_token(',');
 }
@@ -5115,20 +5364,21 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
        assert(entity->base.namespc == NAMESPACE_NORMAL);
        entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL);
        if (previous_entity == NULL
-                       || previous_entity->base.parent_scope != scope) {
+                       || previous_entity->base.parent_scope != current_scope) {
                errorf(HERE, "expected declaration of a function parameter, found '%Y'",
                       symbol);
                return entity;
        }
 
        if (is_definition) {
-               errorf(HERE, "parameter %Y is initialised", entity->base.symbol);
+               errorf(HERE, "parameter '%Y' is initialised", entity->base.symbol);
        }
 
        return record_entity(entity, false);
 }
 
-static void parse_declaration(parsed_declaration_func finished_declaration)
+static void parse_declaration(parsed_declaration_func finished_declaration,
+                              declarator_flags_t      flags)
 {
        declaration_specifiers_t specifiers;
        memset(&specifiers, 0, sizeof(specifiers));
@@ -5140,8 +5390,8 @@ static void parse_declaration(parsed_declaration_func finished_declaration)
        if (token.type == ';') {
                parse_anonymous_declaration_rest(&specifiers);
        } else {
-               entity_t *entity = parse_declarator(&specifiers, /*may_be_abstract=*/false, false);
-               parse_declaration_rest(entity, &specifiers, finished_declaration);
+               entity_t *entity = parse_declarator(&specifiers, flags);
+               parse_declaration_rest(entity, &specifiers, finished_declaration, flags);
        }
 }
 
@@ -5173,24 +5423,36 @@ static void parse_kr_declaration_list(entity_t *entity)
        add_anchor_token('{');
 
        /* push function parameters */
-       size_t const top = environment_top();
-       scope_push(&entity->function.parameters);
+       size_t const  top       = environment_top();
+       scope_t      *old_scope = scope_push(&entity->function.parameters);
 
        entity_t *parameter = entity->function.parameters.entities;
        for ( ; parameter != NULL; parameter = parameter->base.next) {
                assert(parameter->base.parent_scope == NULL);
-               parameter->base.parent_scope = scope;
+               parameter->base.parent_scope = current_scope;
                environment_push(parameter);
        }
 
        /* parse declaration list */
-       while (is_declaration_specifier(&token, false)) {
-               parse_declaration(finished_kr_declaration);
+       for (;;) {
+               switch (token.type) {
+                       DECLARATION_START
+                       case T___extension__:
+                       /* This covers symbols, which are no type, too, and results in
+                        * better error messages.  The typical cases are misspelled type
+                        * names and missing includes. */
+                       case T_IDENTIFIER:
+                               parse_declaration(finished_kr_declaration, DECL_IS_PARAMETER);
+                               break;
+                       default:
+                               goto decl_list_end;
+               }
        }
+decl_list_end:
 
        /* pop function parameters */
-       assert(scope == &entity->function.parameters);
-       scope_pop();
+       assert(current_scope == &entity->function.parameters);
+       scope_pop(old_scope);
        environment_pop_to(top);
 
        /* update function type */
@@ -5199,26 +5461,25 @@ static void parse_kr_declaration_list(entity_t *entity)
        function_parameter_t *parameters     = NULL;
        function_parameter_t *last_parameter = NULL;
 
-       entity_t *parameter_declaration = entity->function.parameters.entities;
-       for( ; parameter_declaration != NULL;
-                       parameter_declaration = parameter_declaration->base.next) {
-               type_t *parameter_type = parameter_declaration->declaration.type;
+       parameter = entity->function.parameters.entities;
+       for (; parameter != NULL; parameter = parameter->base.next) {
+               type_t *parameter_type = parameter->declaration.type;
                if (parameter_type == NULL) {
                        if (strict_mode) {
                                errorf(HERE, "no type specified for function parameter '%Y'",
-                                      parameter_declaration->base.symbol);
+                                      parameter->base.symbol);
                        } else {
                                if (warning.implicit_int) {
                                        warningf(HERE, "no type specified for function parameter '%Y', using 'int'",
-                                                parameter_declaration->base.symbol);
+                                                parameter->base.symbol);
                                }
-                               parameter_type                          = type_int;
-                               parameter_declaration->declaration.type = parameter_type;
+                               parameter_type              = type_int;
+                               parameter->declaration.type = parameter_type;
                        }
                }
 
-               semantic_parameter(&parameter_declaration->declaration);
-               parameter_type = parameter_declaration->declaration.type;
+               semantic_parameter_incomplete(parameter);
+               parameter_type = parameter->declaration.type;
 
                /*
                 * we need the default promoted types for the function type
@@ -5291,8 +5552,6 @@ static void check_labels(void)
                               "label '%Y' used but not defined", label->base.symbol);
                 }
        }
-       goto_first = NULL;
-       goto_last  = NULL;
 
        if (warning.unused_label) {
                for (const label_statement_t *label_statement = label_first;
@@ -5307,11 +5566,9 @@ static void check_labels(void)
                        }
                }
        }
-       label_first = label_last = NULL;
 }
 
-static void warn_unused_decl(entity_t *entity, entity_t *end,
-                             char const *const what)
+static void warn_unused_entity(entity_t *entity, entity_t *end)
 {
        for (; entity != NULL; entity = entity->base.next) {
                if (!is_declaration(entity))
@@ -5323,10 +5580,12 @@ static void warn_unused_decl(entity_t *entity, entity_t *end,
 
                if (!declaration->used) {
                        print_in_function();
+                       const char *what = get_entity_kind_name(entity->kind);
                        warningf(&entity->base.source_position, "%s '%Y' is unused",
                                 what, entity->base.symbol);
                } else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) {
                        print_in_function();
+                       const char *what = get_entity_kind_name(entity->kind);
                        warningf(&entity->base.source_position, "%s '%Y' is never read",
                                 what, entity->base.symbol);
                }
@@ -5343,13 +5602,13 @@ static void check_unused_variables(statement_t *const stmt, void *const env)
        switch (stmt->kind) {
                case STATEMENT_DECLARATION: {
                        declaration_statement_t const *const decls = &stmt->declaration;
-                       warn_unused_decl(decls->declarations_begin, decls->declarations_end,
-                                        "variable");
+                       warn_unused_entity(decls->declarations_begin,
+                                          decls->declarations_end);
                        return;
                }
 
                case STATEMENT_FOR:
-                       warn_unused_decl(stmt->fors.scope.entities, NULL, "variable");
+                       warn_unused_entity(stmt->fors.scope.entities, NULL);
                        return;
 
                default:
@@ -5367,7 +5626,7 @@ static void check_declarations(void)
 
                /* do not issue unused warnings for main */
                if (!is_sym_main(current_function->base.base.symbol)) {
-                       warn_unused_decl(scope->entities, NULL, "parameter");
+                       warn_unused_entity(scope->entities, NULL);
                }
        }
        if (warning.unused_variable) {
@@ -5384,6 +5643,8 @@ static int determine_truth(expression_t const* const cond)
                -1;
 }
 
+static void check_reachable(statement_t *);
+
 static bool expression_returns(expression_t const *const expr)
 {
        switch (expr->kind) {
@@ -5425,16 +5686,24 @@ static bool expression_returns(expression_t const *const expr)
                case EXPR_BUILTIN_PREFETCH:
                case EXPR_OFFSETOF:
                case EXPR_INVALID:
-               case EXPR_STATEMENT: // TODO implement
+                       return true;
+
+               case EXPR_STATEMENT:
+                       check_reachable(expr->statement.statement);
+                       // TODO check if statement can be left
                        return true;
 
                case EXPR_CONDITIONAL:
                        // TODO handle constant expression
-                       return
-                               expression_returns(expr->conditional.condition) && (
-                                       expression_returns(expr->conditional.true_expression) ||
-                                       expression_returns(expr->conditional.false_expression)
-                               );
+
+                       if (!expression_returns(expr->conditional.condition))
+                               return false;
+
+                       if (expr->conditional.true_expression != NULL
+                                       && expression_returns(expr->conditional.true_expression))
+                               return true;
+
+                       return expression_returns(expr->conditional.false_expression);
 
                case EXPR_SELECT:
                        return expression_returns(expr->select.compound);
@@ -5469,6 +5738,31 @@ static bool expression_returns(expression_t const *const expr)
        panic("unhandled expression");
 }
 
+static bool initializer_returns(initializer_t const *const init)
+{
+       switch (init->kind) {
+               case INITIALIZER_VALUE:
+                       return expression_returns(init->value.value);
+
+               case INITIALIZER_LIST: {
+                       initializer_t * const*       i       = init->list.initializers;
+                       initializer_t * const* const end     = i + init->list.len;
+                       bool                         returns = true;
+                       for (; i != end; ++i) {
+                               if (!initializer_returns(*i))
+                                       returns = false;
+                       }
+                       return returns;
+               }
+
+               case INITIALIZER_STRING:
+               case INITIALIZER_WIDE_STRING:
+               case INITIALIZER_DESIGNATOR: // designators have no payload
+                       return true;
+       }
+       panic("unhandled initializer");
+}
+
 static bool noreturn_candidate;
 
 static void check_reachable(statement_t *const stmt)
@@ -5483,23 +5777,49 @@ static void check_reachable(statement_t *const stmt)
        switch (stmt->kind) {
                case STATEMENT_INVALID:
                case STATEMENT_EMPTY:
-               case STATEMENT_DECLARATION:
                case STATEMENT_LOCAL_LABEL:
                case STATEMENT_ASM:
                        next = stmt->base.next;
                        break;
 
+               case STATEMENT_DECLARATION: {
+                       declaration_statement_t const *const decl = &stmt->declaration;
+                       entity_t                const *      ent  = decl->declarations_begin;
+                       entity_t                const *const last = decl->declarations_end;
+                       if (ent != NULL) {
+                               for (;; ent = ent->base.next) {
+                                       if (ent->kind                 == ENTITY_VARIABLE &&
+                                                       ent->variable.initializer != NULL            &&
+                                                       !initializer_returns(ent->variable.initializer)) {
+                                               return;
+                                       }
+                                       if (ent == last)
+                                               break;
+                               }
+                       }
+                       next = stmt->base.next;
+                       break;
+               }
+
                case STATEMENT_COMPOUND:
                        next = stmt->compound.statements;
                        break;
 
-               case STATEMENT_RETURN:
-                       noreturn_candidate = false;
+               case STATEMENT_RETURN: {
+                       expression_t const *const val = stmt->returns.value;
+                       if (val == NULL || expression_returns(val))
+                               noreturn_candidate = false;
                        return;
+               }
 
                case STATEMENT_IF: {
-                       if_statement_t const* const ifs = &stmt->ifs;
-                       int            const        val = determine_truth(ifs->condition);
+                       if_statement_t const *const ifs  = &stmt->ifs;
+                       expression_t   const *const cond = ifs->condition;
+
+                       if (!expression_returns(cond))
+                               return;
+
+                       int const val = determine_truth(cond);
 
                        if (val >= 0)
                                check_reachable(ifs->true_statement);
@@ -5520,6 +5840,9 @@ static void check_reachable(statement_t *const stmt)
                        switch_statement_t const *const switchs = &stmt->switchs;
                        expression_t       const *const expr    = switchs->expression;
 
+                       if (!expression_returns(expr))
+                               return;
+
                        if (is_constant_expression(expr)) {
                                long                    const val      = fold_constant(expr);
                                case_label_statement_t *      defaults = NULL;
@@ -5609,6 +5932,9 @@ found_break_parent:
 
                case STATEMENT_GOTO:
                        if (stmt->gotos.expression) {
+                               if (!expression_returns(stmt->gotos.expression))
+                                       return;
+
                                statement_t *parent = stmt->base.parent;
                                if (parent == NULL) /* top level goto */
                                        return;
@@ -5630,7 +5956,12 @@ found_break_parent:
 
                case STATEMENT_WHILE: {
                        while_statement_t const *const whiles = &stmt->whiles;
-                       int                      const val    = determine_truth(whiles->condition);
+                       expression_t      const *const cond   = whiles->condition;
+
+                       if (!expression_returns(cond))
+                               return;
+
+                       int const val = determine_truth(cond);
 
                        if (val >= 0)
                                check_reachable(whiles->body);
@@ -5654,8 +5985,15 @@ found_break_parent:
                        fors->condition_reachable = true;
 
                        expression_t const *const cond = fors->condition;
-                       int          const        val  =
-                               cond == NULL ? 1 : determine_truth(cond);
+
+                       int val;
+                       if (cond == NULL) {
+                               val = 1;
+                       } else if (expression_returns(cond)) {
+                               val = determine_truth(cond);
+                       } else {
+                               return;
+                       }
 
                        if (val >= 0)
                                check_reachable(fors->body);
@@ -5739,7 +6077,12 @@ continue_while:
                                next->base.reachable = true;
 
                                while_statement_t const *const whiles = &next->whiles;
-                               int                      const val    = determine_truth(whiles->condition);
+                               expression_t      const *const cond   = whiles->condition;
+
+                               if (!expression_returns(cond))
+                                       return;
+
+                               int const val = determine_truth(cond);
 
                                if (val >= 0)
                                        check_reachable(whiles->body);
@@ -5758,8 +6101,13 @@ continue_do_while:
                                        return;
                                next->base.reachable = true;
 
-                               do_while_statement_t const *const dw  = &next->do_while;
-                               int                  const        val = determine_truth(dw->condition);
+                               do_while_statement_t const *const dw   = &next->do_while;
+                               expression_t         const *const cond = dw->condition;
+
+                               if (!expression_returns(cond))
+                                       return;
+
+                               int const val = determine_truth(cond);
 
                                if (val >= 0)
                                        check_reachable(dw->body);
@@ -5783,8 +6131,15 @@ continue_for:;
                                fors->condition_reachable = true;
 
                                expression_t const *const cond = fors->condition;
-                               int          const        val  =
-                                       cond == NULL ? 1 : determine_truth(cond);
+
+                               int val;
+                               if (cond == NULL) {
+                                       val = 1;
+                               } else if (expression_returns(cond)) {
+                                       val = determine_truth(cond);
+                               } else {
+                                       return;
+                               }
 
                                if (val >= 0)
                                        check_reachable(fors->body);
@@ -5850,9 +6205,26 @@ static void check_unreachable(statement_t* const stmt, void *const env)
                case STATEMENT_COMPOUND:
                        if (stmt->compound.statements != NULL)
                                return;
-                       /* FALLTHROUGH*/
+                       goto warn_unreachable;
+
+               case STATEMENT_DECLARATION: {
+                       /* Only warn if there is at least one declarator with an initializer.
+                        * This typically occurs in switch statements. */
+                       declaration_statement_t const *const decl = &stmt->declaration;
+                       entity_t                const *      ent  = decl->declarations_begin;
+                       entity_t                const *const last = decl->declarations_end;
+                       for (;; ent = ent->base.next) {
+                               if (ent->kind                 == ENTITY_VARIABLE &&
+                                               ent->variable.initializer != NULL) {
+                                       goto warn_unreachable;
+                               }
+                               if (ent == last)
+                                       return;
+                       }
+               }
 
                default:
+warn_unreachable:
                        if (!stmt->base.reachable)
                                warningf(&stmt->base.source_position, "statement is unreachable");
                        return;
@@ -5882,7 +6254,7 @@ static void parse_external_declaration(void)
        add_anchor_token('{');
 
        /* declarator is common to both function-definitions and declarations */
-       entity_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false, false);
+       entity_t *ndeclaration = parse_declarator(&specifiers, DECL_FLAGS_NONE);
 
        rem_anchor_token('{');
        rem_anchor_token(';');
@@ -5894,7 +6266,8 @@ static void parse_external_declaration(void)
                case ',':
                case ';':
                case '=':
-                       parse_declaration_rest(ndeclaration, &specifiers, record_entity);
+                       parse_declaration_rest(ndeclaration, &specifiers, record_entity,
+                                       DECL_FLAGS_NONE);
                        return;
        }
 
@@ -5908,11 +6281,9 @@ static void parse_external_declaration(void)
        }
 
        assert(is_declaration(ndeclaration));
-       type_t *type = ndeclaration->declaration.type;
+       type_t *type = skip_typeref(ndeclaration->declaration.type);
 
-       /* note that we don't skip typerefs: the standard doesn't allow them here
-        * (so we can't use is_type_function here) */
-       if (type->kind != TYPE_FUNCTION) {
+       if (!is_type_function(type)) {
                if (is_type_valid(type)) {
                        errorf(HERE, "declarator '%#T' has a body but is not a function type",
                               type, ndeclaration->base.symbol);
@@ -5962,17 +6333,17 @@ static void parse_external_declaration(void)
        type = skip_typeref(entity->declaration.type);
 
        /* push function parameters and switch scope */
-       size_t const top = environment_top();
-       scope_push(&function->parameters);
+       size_t const  top       = environment_top();
+       scope_t      *old_scope = scope_push(&function->parameters);
 
        entity_t *parameter = function->parameters.entities;
-       for; parameter != NULL; parameter = parameter->base.next) {
+       for (; parameter != NULL; parameter = parameter->base.next) {
                if (parameter->base.parent_scope == &ndeclaration->function.parameters) {
-                       parameter->base.parent_scope = scope;
+                       parameter->base.parent_scope = current_scope;
                }
                assert(parameter->base.parent_scope == NULL
-                               || parameter->base.parent_scope == scope);
-               parameter->base.parent_scope = scope;
+                               || parameter->base.parent_scope == current_scope);
+               parameter->base.parent_scope = current_scope;
                if (parameter->base.symbol == NULL) {
                        errorf(&parameter->base.source_position, "parameter name omitted");
                        continue;
@@ -5990,7 +6361,12 @@ static void parse_external_declaration(void)
                current_function                 = function;
                current_parent                   = NULL;
 
-               statement_t *const body     = parse_compound_statement(false);
+               goto_first   = NULL;
+               goto_anchor  = &goto_first;
+               label_first  = NULL;
+               label_anchor = &label_first;
+
+               statement_t *const body = parse_compound_statement(false);
                function->statement = body;
                first_err = true;
                check_labels();
@@ -6018,8 +6394,8 @@ static void parse_external_declaration(void)
                label_pop_to(label_stack_top);
        }
 
-       assert(scope == &function->parameters);
-       scope_pop();
+       assert(current_scope == &function->parameters);
+       scope_pop(old_scope);
        environment_pop_to(top);
 }
 
@@ -6046,14 +6422,11 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
                long v = fold_constant(size);
 
                if (v < 0) {
-                       errorf(source_position, "negative width in bit-field '%Y'",
-                               symbol);
+                       errorf(source_position, "negative width in bit-field '%Y'", symbol);
                } else if (v == 0) {
-                       errorf(source_position, "zero width for bit-field '%Y'",
-                               symbol);
+                       errorf(source_position, "zero width for bit-field '%Y'", symbol);
                } else if (bit_size > 0 && (il_size_t)v > bit_size) {
-                       errorf(source_position, "width of '%Y' exceeds its type",
-                               symbol);
+                       errorf(source_position, "width of '%Y' exceeds its type", symbol);
                } else {
                        type->bitfield.bit_size = v;
                }
@@ -6065,11 +6438,13 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
 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) {
+       for (; iter != NULL; iter = iter->base.next) {
                if (iter->kind != ENTITY_COMPOUND_MEMBER)
                        continue;
 
-               if (iter->base.symbol == NULL) {
+               if (iter->base.symbol == symbol) {
+                       return iter;
+               } else if (iter->base.symbol == NULL) {
                        type_t *type = skip_typeref(iter->declaration.type);
                        if (is_type_compound(type)) {
                                entity_t *result
@@ -6079,10 +6454,6 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
                        }
                        continue;
                }
-
-               if (iter->base.symbol == symbol) {
-                       return iter;
-               }
        }
 
        return NULL;
@@ -6112,7 +6483,8 @@ static void parse_compound_declarators(compound_t *compound,
                        entity->declaration.modifiers              = specifiers->modifiers;
                        entity->declaration.type                   = type;
                } else {
-                       entity = parse_declarator(specifiers,/*may_be_abstract=*/true, true);
+                       entity = parse_declarator(specifiers,
+                                       DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
                        assert(entity->kind == ENTITY_COMPOUND_MEMBER);
 
                        if (token.type == ':') {
@@ -6133,7 +6505,6 @@ static void parse_compound_declarators(compound_t *compound,
                        entity_t *prev = find_compound_entry(compound, symbol);
 
                        if (prev != NULL) {
-                               assert(prev->base.symbol == symbol);
                                errorf(&entity->base.source_position,
                                       "multiple declarations of symbol '%Y' (declared %P)",
                                       symbol, &prev->base.source_position);
@@ -6142,40 +6513,33 @@ static void parse_compound_declarators(compound_t *compound,
 
                append_entity(&compound->members, entity);
 
-               if (token.type != ',')
-                       break;
-               next_token();
-       }
-       expect(';');
-
-end_error:
-       ;
-}
-
-static void semantic_compound(compound_t *compound)
-{
-       entity_t *entity = compound->members.entities;
-       for ( ; entity != NULL; entity = entity->base.next) {
-               assert(entity->kind == ENTITY_COMPOUND_MEMBER);
-
                type_t *orig_type = entity->declaration.type;
                type_t *type      = skip_typeref(orig_type);
-
                if (is_type_function(type)) {
-                       errorf(HERE,
-                              "compound member '%Y' must not have function type '%T'",
-                              entity->base.symbol, orig_type);
+                       errorf(&entity->base.source_position,
+                                       "compound member '%Y' must not have function type '%T'",
+                                       entity->base.symbol, orig_type);
                } else if (is_type_incomplete(type)) {
-                       /* Â§6.7.2.1 (16) flexible array member */
-                       if (is_type_array(type) && entity->base.next == NULL) {
+                       /* Â§6.7.2.1:16 flexible array member */
+                       if (is_type_array(type) &&
+                                       token.type == ';'   &&
+                                       look_ahead(1)->type == '}') {
                                compound->has_flexible_member = true;
                        } else {
-                               errorf(HERE,
-                                      "compound member '%Y' has incomplete type '%T'",
-                                      entity->base.symbol, orig_type);
+                               errorf(&entity->base.source_position,
+                                               "compound member '%Y' has incomplete type '%T'",
+                                               entity->base.symbol, orig_type);
                        }
                }
+
+               if (token.type != ',')
+                       break;
+               next_token();
        }
+       expect(';', end_error);
+
+end_error:
+       anonymous_entity = NULL;
 }
 
 static void parse_compound_type_entries(compound_t *compound)
@@ -6194,9 +6558,11 @@ static void parse_compound_type_entries(compound_t *compound)
 
                parse_compound_declarators(compound, &specifiers);
        }
-       semantic_compound(compound);
        rem_anchor_token('}');
        next_token();
+
+       /* Â§6.7.2.1:7 */
+       compound->complete = true;
 }
 
 static type_t *parse_typename(void)
@@ -6204,7 +6570,8 @@ static type_t *parse_typename(void)
        declaration_specifiers_t specifiers;
        memset(&specifiers, 0, sizeof(specifiers));
        parse_declaration_specifiers(&specifiers);
-       if (specifiers.storage_class != STORAGE_CLASS_NONE) {
+       if (specifiers.storage_class != STORAGE_CLASS_NONE ||
+                       specifiers.thread_local) {
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
@@ -6238,7 +6605,7 @@ 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);
+               errorf(HERE, "expected expression, got token %K", &token);
        }
        next_token();
 
@@ -6333,10 +6700,10 @@ static expression_t *parse_character_constant(void)
        cnst->conste.v.character = token.v.string;
 
        if (cnst->conste.v.character.size != 1) {
-               if (warning.multichar && GNU_MODE) {
+               if (!GNU_MODE) {
+                       errorf(HERE, "more than 1 character in character constant");
+               } else if (warning.multichar) {
                        warningf(HERE, "multi-character character constant");
-               } else {
-                       errorf(HERE, "more than 1 characters in character constant");
                }
        }
        next_token();
@@ -6354,10 +6721,10 @@ static expression_t *parse_wide_character_constant(void)
        cnst->conste.v.wide_character = token.v.wide_string;
 
        if (cnst->conste.v.wide_character.size != 1) {
-               if (warning.multichar && GNU_MODE) {
+               if (!GNU_MODE) {
+                       errorf(HERE, "more than 1 character in character constant");
+               } else if (warning.multichar) {
                        warningf(HERE, "multi-character character constant");
-               } else {
-                       errorf(HERE, "more than 1 characters in character constant");
                }
        }
        next_token();
@@ -6506,7 +6873,7 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
        case T___builtin_expect:
                return make_function_2_type(type_long, type_long, type_long);
        default:
-               internal_errorf(HERE, "not implemented builtin symbol found");
+               internal_errorf(HERE, "not implemented builtin identifier found");
        }
 }
 
@@ -6606,14 +6973,15 @@ static expression_t *parse_reference(void)
        if (entity == NULL) {
                if (!strict_mode && look_ahead(1)->type == '(') {
                        /* an implicitly declared function */
-                       if (warning.implicit_function_declaration) {
-                               warningf(HERE, "implicit declaration of function '%Y'",
-                                       symbol);
+                       if (warning.error_implicit_function_declaration) {
+                               errorf(HERE, "implicit declaration of function '%Y'", symbol);
+                       } else if (warning.implicit_function_declaration) {
+                               warningf(HERE, "implicit declaration of function '%Y'", symbol);
                        }
 
                        entity = create_implicit_function(symbol, HERE);
                } else {
-                       errorf(HERE, "unknown symbol '%Y' found.", symbol);
+                       errorf(HERE, "unknown identifier '%Y' found.", symbol);
                        entity = create_error_entity(symbol, ENTITY_VARIABLE);
                }
        }
@@ -6656,6 +7024,8 @@ static expression_t *parse_reference(void)
                if (entity->kind == ENTITY_VARIABLE) {
                        /* access of a variable from an outer function */
                        entity->variable.address_taken = true;
+               } else if (entity->kind == ENTITY_PARAMETER) {
+                       entity->parameter.address_taken = true;
                }
                current_function->need_closure = true;
        }
@@ -6768,7 +7138,7 @@ static expression_t *parse_cast(void)
        type_t *type = parse_typename();
 
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
        if (token.type == '{') {
                return parse_compound_literal(type);
@@ -6818,7 +7188,7 @@ static expression_t *parse_statement_expression(void)
        expression->base.type = type;
 
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
 end_error:
        return expression;
@@ -6848,7 +7218,7 @@ static expression_t *parse_parenthesized_expression(void)
        add_anchor_token(')');
        expression_t *result = parse_expression();
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
 end_error:
        return result;
@@ -6930,7 +7300,7 @@ static designator_t *parse_designator(void)
        next_token();
 
        designator_t *last_designator = result;
-       while(true) {
+       while (true) {
                if (token.type == '.') {
                        next_token();
                        if (token.type != T_IDENTIFIER) {
@@ -6954,7 +7324,7 @@ static designator_t *parse_designator(void)
                        designator->source_position = *HERE;
                        designator->array_index     = parse_expression();
                        rem_anchor_token(']');
-                       expect(']');
+                       expect(']', end_error);
                        if (designator->array_index == NULL) {
                                return NULL;
                        }
@@ -6981,15 +7351,15 @@ static expression_t *parse_offsetof(void)
 
        eat(T___builtin_offsetof);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(',');
        type_t *type = parse_typename();
        rem_anchor_token(',');
-       expect(',');
+       expect(',', end_error);
        add_anchor_token(')');
        designator_t *designator = parse_designator();
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
        expression->offsetofe.type       = type;
        expression->offsetofe.designator = designator;
@@ -7021,26 +7391,26 @@ static expression_t *parse_va_start(void)
 
        eat(T___builtin_va_start);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(',');
        expression->va_starte.ap = parse_assignment_expression();
        rem_anchor_token(',');
-       expect(',');
+       expect(',', end_error);
        expression_t *const expr = parse_assignment_expression();
        if (expr->kind == EXPR_REFERENCE) {
                entity_t *const entity = expr->reference.entity;
                if (entity->base.parent_scope != &current_function->parameters
                                || entity->base.next != NULL
-                               || entity->kind != ENTITY_VARIABLE) {
+                               || entity->kind != ENTITY_PARAMETER) {
                        errorf(&expr->base.source_position,
                               "second argument of 'va_start' must be last parameter of the current function");
                } else {
                        expression->va_starte.parameter = &entity->variable;
                }
-               expect(')');
+               expect(')', end_error);
                return expression;
        }
-       expect(')');
+       expect(')', end_error);
 end_error:
        return create_invalid_expression();
 }
@@ -7054,11 +7424,11 @@ static expression_t *parse_va_arg(void)
 
        eat(T___builtin_va_arg);
 
-       expect('(');
+       expect('(', end_error);
        expression->va_arge.ap = parse_assignment_expression();
-       expect(',');
+       expect(',', end_error);
        expression->base.type = parse_typename();
-       expect(')');
+       expect(')', end_error);
 
        return expression;
 end_error:
@@ -7090,11 +7460,11 @@ static expression_t *parse_builtin_constant(void)
 
        eat(T___builtin_constant_p);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        expression->builtin_constant.value = parse_assignment_expression();
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
        expression->base.type = type_int;
 
        return expression;
@@ -7111,7 +7481,7 @@ static expression_t *parse_builtin_prefetch(void)
 
        eat(T___builtin_prefetch);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        expression->builtin_prefetch.adr = parse_assignment_expression();
        if (token.type == ',') {
@@ -7123,7 +7493,7 @@ static expression_t *parse_builtin_prefetch(void)
                expression->builtin_prefetch.locality = parse_assignment_expression();
        }
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
        expression->base.type = type_void;
 
        return expression;
@@ -7163,11 +7533,11 @@ static expression_t *parse_compare_builtin(void)
        expression->base.source_position = *HERE;
        next_token();
 
-       expect('(');
+       expect('(', end_error);
        expression->binary.left = parse_assignment_expression();
-       expect(',');
+       expect(',', end_error);
        expression->binary.right = parse_assignment_expression();
-       expect(')');
+       expect(')', end_error);
 
        type_t *const orig_type_left  = expression->binary.left->base.type;
        type_t *const orig_type_right = expression->binary.right->base.type;
@@ -7190,20 +7560,20 @@ end_error:
 
 #if 0
 /**
- * Parses a __builtin_expect() expression.
+ * Parses a __builtin_expect(, end_error) expression.
  */
-static expression_t *parse_builtin_expect(void)
+static expression_t *parse_builtin_expect(void, end_error)
 {
        expression_t *expression
                = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT);
 
        eat(T___builtin_expect);
 
-       expect('(');
+       expect('(', end_error);
        expression->binary.left = parse_assignment_expression();
-       expect(',');
+       expect(',', end_error);
        expression->binary.right = parse_constant_expression();
-       expect(')');
+       expect(')', end_error);
 
        expression->base.type = expression->binary.left->base.type;
 
@@ -7222,11 +7592,11 @@ static expression_t *parse_assume(void)
 
        eat(T__assume);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        expression->unary.value = parse_assignment_expression();
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
        expression->base.type = type_void;
        return expression;
@@ -7244,11 +7614,11 @@ static label_t *get_label(symbol_t *symbol)
        entity_t *label;
        assert(current_function != NULL);
 
-       label = get_entity(symbol, NAMESPACE_LOCAL_LABEL);
+       label = get_entity(symbol, NAMESPACE_LABEL);
        /* if we found a local label, we already created the declaration */
        if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
-               if (label->base.parent_scope != scope) {
-                       assert(label->base.parent_scope->depth < scope->depth);
+               if (label->base.parent_scope != current_scope) {
+                       assert(label->base.parent_scope->depth < current_scope->depth);
                        current_function->goto_to_outer = true;
                }
                return &label->label;
@@ -7321,7 +7691,7 @@ static expression_t *parse_noop_expression(void)
                add_anchor_token(',');
 
                if (token.type != ')') {
-                       while(true) {
+                       while (true) {
                                (void)parse_assignment_expression();
                                if (token.type != ',')
                                        break;
@@ -7331,7 +7701,7 @@ static expression_t *parse_noop_expression(void)
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
 end_error:
        return cnst;
@@ -7449,7 +7819,7 @@ static expression_t *parse_array_expression(expression_t *left)
        expression->base.type = automatic_type_conversion(return_type);
 
        rem_anchor_token(']');
-       expect(']');
+       expect(']', end_error);
 end_error:
        return expression;
 }
@@ -7461,8 +7831,6 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
 
        eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
 
-       char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
-
        /* we only refer to a type property, mark this case */
        bool old     = in_type_prop;
        in_type_prop = true;
@@ -7474,7 +7842,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
                add_anchor_token(')');
                orig_type = parse_typename();
                rem_anchor_token(')');
-               expect(')');
+               expect(')', end_error);
 
                if (token.type == '{') {
                        /* It was not sizeof(type) after all.  It is sizeof of an expression
@@ -7500,6 +7868,7 @@ typeprop_expression:
                type->kind == TYPE_BITFIELD ? "bitfield"            :
                NULL;
        if (wrong_type != NULL) {
+               char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
                errorf(&tp_expression->base.source_position,
                                "operand of %s expression must not be of %s type '%T'",
                                what, wrong_type, orig_type);
@@ -7580,7 +7949,7 @@ static expression_t *parse_select_expression(expression_t *compound)
                               symbol, type_left);
                }
 create_error_entry:
-               return create_invalid_expression();
+               entry = create_error_entity(symbol, ENTITY_COMPOUND_MEMBER);
        }
 
        assert(is_declaration(entry));
@@ -7715,7 +8084,7 @@ static expression_t *parse_call_expression(expression_t *expression)
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
 
        if (function_type == NULL)
                return result;
@@ -7736,7 +8105,7 @@ static expression_t *parse_call_expression(expression_t *expression)
        }
 
        /* do default promotion */
-       for; argument != NULL; argument = argument->next) {
+       for (; argument != NULL; argument = argument->next) {
                type_t *type = argument->expression->base.type;
 
                type = get_default_promoted_type(type);
@@ -7767,6 +8136,60 @@ static bool same_compound_type(const type_t *type1, const type_t *type2)
                type1->compound.compound == type2->compound.compound;
 }
 
+static expression_t const *get_reference_address(expression_t const *expr)
+{
+       bool regular_take_address = true;
+       for (;;) {
+               if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+                       expr = expr->unary.value;
+               } else {
+                       regular_take_address = false;
+               }
+
+               if (expr->kind != EXPR_UNARY_DEREFERENCE)
+                       break;
+
+               expr = expr->unary.value;
+       }
+
+       if (expr->kind != EXPR_REFERENCE)
+               return NULL;
+
+       /* special case for functions which are automatically converted to a
+        * pointer to function without an extra TAKE_ADDRESS operation */
+       if (!regular_take_address &&
+                       expr->reference.entity->kind != ENTITY_FUNCTION) {
+               return NULL;
+       }
+
+       return expr;
+}
+
+static void warn_reference_address_as_bool(expression_t const* expr)
+{
+       if (!warning.address)
+               return;
+
+       expr = get_reference_address(expr);
+       if (expr != NULL) {
+               warningf(&expr->base.source_position,
+                        "the address of '%Y' will always evaluate as 'true'",
+                        expr->reference.entity->base.symbol);
+       }
+}
+
+static void semantic_condition(expression_t const *const expr,
+                               char const *const context)
+{
+       type_t *const type = skip_typeref(expr->base.type);
+       if (is_type_scalar(type)) {
+               warn_reference_address_as_bool(expr);
+       } else if (is_type_valid(type)) {
+               errorf(&expr->base.source_position,
+                               "%s must have scalar type", context);
+       }
+}
+
 /**
  * Parse a conditional expression, ie. 'expression ? ... : ...'.
  *
@@ -7782,13 +8205,8 @@ static expression_t *parse_conditional_expression(expression_t *expression)
        eat('?');
        add_anchor_token(':');
 
-       /* 6.5.15.2 */
-       type_t *const condition_type_orig = expression->base.type;
-       type_t *const condition_type      = skip_typeref(condition_type_orig);
-       if (!is_type_scalar(condition_type) && is_type_valid(condition_type)) {
-               type_error("expected a scalar type in conditional condition",
-                          &expression->base.source_position, condition_type_orig);
-       }
+       /* Â§6.5.15:2  The first operand shall have scalar type. */
+       semantic_condition(expression, "condition of conditional operator");
 
        expression_t *true_expression = expression;
        bool          gnu_cond = false;
@@ -7798,7 +8216,7 @@ static expression_t *parse_conditional_expression(expression_t *expression)
                true_expression = parse_expression();
        }
        rem_anchor_token(':');
-       expect(':');
+       expect(':', end_error);
        expression_t *false_expression =
                parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
 
@@ -7935,11 +8353,11 @@ static expression_t *parse_builtin_classify_type(void)
 
        eat(T___builtin_classify_type);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        expression_t *expression = parse_expression();
        rem_anchor_token(')');
-       expect(')');
+       expect(')', end_error);
        result->classify_type.type_expression = expression;
 
        return result;
@@ -7961,7 +8379,7 @@ static expression_t *parse_delete(void)
        if (token.type == '[') {
                next_token();
                result->kind = EXPR_UNARY_DELETE_ARRAY;
-               expect(']');
+               expect(']', end_error);
 end_error:;
        }
 
@@ -8063,11 +8481,16 @@ static bool is_lvalue(const expression_t *expression)
        case EXPR_UNARY_DEREFERENCE:
                return true;
 
-       default:
+       default: {
+         type_t *type = skip_typeref(expression->base.type);
+         return
+               /* ISO/IEC 14882:1998(E) Â§3.10:3 */
+               is_type_reference(type) ||
                /* Claim it is an lvalue, if the type is invalid.  There was a parse
                 * error before, which maybe prevented properly recognizing it as
                 * lvalue. */
-               return !is_type_valid(skip_typeref(expression->base.type));
+               !is_type_valid(type);
+       }
        }
 }
 
@@ -8117,56 +8540,10 @@ static void semantic_unexpr_plus(unary_expression_t *expression)
                        "traditional C rejects the unary plus operator");
 }
 
-static expression_t const *get_reference_address(expression_t const *expr)
-{
-       bool regular_take_address = true;
-       for (;;) {
-               if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
-                       expr = expr->unary.value;
-               } else {
-                       regular_take_address = false;
-               }
-
-               if (expr->kind != EXPR_UNARY_DEREFERENCE)
-                       break;
-
-               expr = expr->unary.value;
-       }
-
-       /* special case for functions which are automatically converted to a
-        * pointer to function without an extra TAKE_ADDRESS operation */
-       if (!regular_take_address && expr->kind == EXPR_REFERENCE
-                       && expr->reference.entity->kind == ENTITY_FUNCTION) {
-               return expr;
-       }
-
-       return NULL;
-}
-
-static void warn_function_address_as_bool(expression_t const* expr)
-{
-       if (!warning.address)
-               return;
-
-       expr = get_reference_address(expr);
-       if (expr != NULL) {
-               warningf(&expr->base.source_position,
-                        "the address of '%Y' will always evaluate as 'true'",
-                        expr->reference.entity->base.symbol);
-       }
-}
-
 static void semantic_not(unary_expression_t *expression)
 {
-       type_t *const orig_type = expression->value->base.type;
-       type_t *const type      = skip_typeref(orig_type);
-       if (!is_type_scalar(type) && is_type_valid(type)) {
-               errorf(&expression->base.source_position,
-                      "operand of ! must be of scalar type");
-       }
-
-       warn_function_address_as_bool(expression->value);
-
+       /* Â§6.5.3.3:1  The operand [...] of the ! operator, scalar type. */
+       semantic_condition(expression->value, "operand of !");
        expression->base.type = c_mode & _CXX ? type_bool : type_int;
 }
 
@@ -8215,17 +8592,22 @@ static void set_address_taken(expression_t *expression, bool may_be_register)
 
        entity_t *const entity = expression->reference.entity;
 
-       if (entity->kind != ENTITY_VARIABLE)
+       if (entity->kind != ENTITY_VARIABLE && entity->kind != ENTITY_PARAMETER)
                return;
 
        if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
                        && !may_be_register) {
                errorf(&expression->base.source_position,
-                               "address of register variable '%Y' requested",
-                               entity->base.symbol);
+                               "address of register %s '%Y' requested",
+                               get_entity_kind_name(entity->kind),     entity->base.symbol);
        }
 
-       entity->variable.address_taken = true;
+       if (entity->kind == ENTITY_VARIABLE) {
+               entity->variable.address_taken = true;
+       } else {
+               assert(entity->kind == ENTITY_PARAMETER);
+               entity->parameter.address_taken = true;
+       }
 }
 
 /**
@@ -8242,11 +8624,8 @@ static void semantic_take_addr(unary_expression_t *expression)
                return;
 
        /* Â§6.5.3.2 */
-       if (value->kind != EXPR_ARRAY_ACCESS
-                       && value->kind != EXPR_UNARY_DEREFERENCE
-                       && !is_lvalue(value)) {
-               errorf(&expression->base.source_position,
-                      "'&' requires an lvalue");
+       if (!is_lvalue(value)) {
+               errorf(&expression->base.source_position, "'&' requires an lvalue");
        }
        if (type->kind == TYPE_BITFIELD) {
                errorf(&expression->base.source_position,
@@ -8662,8 +9041,14 @@ static bool is_valid_assignment_lhs(expression_t const* const left)
                return false;
        }
 
+       if (left->kind == EXPR_REFERENCE
+                       && left->reference.entity->kind == ENTITY_FUNCTION) {
+               errorf(HERE, "cannot assign to function '%E'", left);
+               return false;
+       }
+
        if (is_type_array(type_left)) {
-               errorf(HERE, "cannot assign to arrays ('%E')", left);
+               errorf(HERE, "cannot assign to array '%E'", left);
                return false;
        }
        if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
@@ -8758,25 +9143,10 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
  */
 static void semantic_logical_op(binary_expression_t *expression)
 {
-       expression_t *const left            = expression->left;
-       expression_t *const right           = expression->right;
-       type_t       *const orig_type_left  = left->base.type;
-       type_t       *const orig_type_right = right->base.type;
-       type_t       *const type_left       = skip_typeref(orig_type_left);
-       type_t       *const type_right      = skip_typeref(orig_type_right);
-
-       warn_function_address_as_bool(left);
-       warn_function_address_as_bool(right);
-
-       if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
-               /* TODO: improve error message */
-               if (is_type_valid(type_left) && is_type_valid(type_right)) {
-                       errorf(&expression->base.source_position,
-                              "operation needs scalar types");
-               }
-               return;
-       }
-
+       /* Â§6.5.13:2  Each of the operands shall have scalar type.
+        * Â§6.5.14:2  Each of the operands shall have scalar type. */
+       semantic_condition(expression->left,   "left operand of logical operator");
+       semantic_condition(expression->right, "right operand of logical operator");
        expression->base.type = c_mode & _CXX ? type_bool : type_int;
 }
 
@@ -8923,7 +9293,6 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_BINARY_COMMA:
                        return expression_has_effect(expr->binary.right);
 
-               case EXPR_BINARY_BUILTIN_EXPECT:     return true;
                case EXPR_BINARY_ISGREATER:          return false;
                case EXPR_BINARY_ISGREATEREQUAL:     return false;
                case EXPR_BINARY_ISLESS:             return false;
@@ -9016,7 +9385,7 @@ static expression_t *parse_sub_expression(precedence_t precedence)
        assert(left != NULL);
        left->base.source_position = source_position;
 
-       while(true) {
+       while (true) {
                if (token.type < 0) {
                        return expected_expression_error();
                }
@@ -9150,8 +9519,8 @@ static void init_expression_parsers(void)
  */
 static asm_argument_t *parse_asm_arguments(bool is_out)
 {
-       asm_argument_t *result = NULL;
-       asm_argument_t *last   = NULL;
+       asm_argument_t  *result = NULL;
+       asm_argument_t **anchor = &result;
 
        while (token.type == T_STRING_LITERAL || token.type == '[') {
                asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
@@ -9166,11 +9535,11 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                        }
                        argument->symbol = token.v.symbol;
 
-                       expect(']');
+                       expect(']', end_error);
                }
 
                argument->constraints = parse_string_literals();
-               expect('(');
+               expect('(', end_error);
                add_anchor_token(')');
                expression_t *expression = parse_expression();
                rem_anchor_token(')');
@@ -9230,16 +9599,12 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                        mark_vars_read(expression, NULL);
                }
                argument->expression = expression;
-               expect(')');
+               expect(')', end_error);
 
                set_address_taken(expression, true);
 
-               if (last != NULL) {
-                       last->next = argument;
-               } else {
-                       result = argument;
-               }
-               last = argument;
+               *anchor = argument;
+               anchor  = &argument->next;
 
                if (token.type != ',')
                        break;
@@ -9259,7 +9624,7 @@ static asm_clobber_t *parse_asm_clobbers(void)
        asm_clobber_t *result = NULL;
        asm_clobber_t *last   = NULL;
 
-       while(token.type == T_STRING_LITERAL) {
+       while (token.type == T_STRING_LITERAL) {
                asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
                clobber->clobber       = parse_string_literals();
 
@@ -9293,7 +9658,7 @@ static statement_t *parse_asm_statement(void)
                asm_statement->is_volatile = true;
        }
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        add_anchor_token(':');
        asm_statement->asm_text = parse_string_literals();
@@ -9323,8 +9688,8 @@ static statement_t *parse_asm_statement(void)
 
 end_of_asm:
        rem_anchor_token(')');
-       expect(')');
-       expect(';');
+       expect(')', end_error);
+       expect(';', end_error);
 
        if (asm_statement->outputs == NULL) {
                /* GCC: An 'asm' instruction without any output operands will be treated
@@ -9390,7 +9755,8 @@ static statement_t *parse_case_statement(void)
 
        PUSH_PARENT(statement);
 
-       expect(':');
+       expect(':', end_error);
+end_error:
 
        if (current_switch != NULL) {
                if (! statement->case_label.is_bad) {
@@ -9427,9 +9793,6 @@ static statement_t *parse_case_statement(void)
 
        POP_PARENT;
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 /**
@@ -9443,7 +9806,7 @@ static statement_t *parse_default_statement(void)
 
        PUSH_PARENT(statement);
 
-       expect(':');
+       expect(':', end_error);
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
                if (def_label != NULL) {
@@ -9531,12 +9894,8 @@ static statement_t *parse_label_statement(void)
        }
 
        /* remember the labels in a list for later checking */
-       if (label_last == NULL) {
-               label_first = &statement->label;
-       } else {
-               label_last->next = &statement->label;
-       }
-       label_last = &statement->label;
+       *label_anchor = &statement->label;
+       label_anchor  = &statement->label.next;
 
        POP_PARENT;
        return statement;
@@ -9555,13 +9914,16 @@ static statement_t *parse_if(void)
 
        add_anchor_token('{');
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        expression_t *const expr = parse_expression();
        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(')');
+       expect(')', end_error);
 
 end_error:
        rem_anchor_token('{');
@@ -9631,7 +9993,7 @@ static statement_t *parse_switch(void)
 
        PUSH_PARENT(statement);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        expression_t *const expr = parse_expression();
        mark_vars_read(expr, NULL);
@@ -9651,7 +10013,7 @@ static statement_t *parse_switch(void)
                type = type_error_type;
        }
        statement->switchs.expression = create_implicit_cast(expr, type);
-       expect(')');
+       expect(')', end_error);
        rem_anchor_token(')');
 
        switch_statement_t *rem = current_switch;
@@ -9695,13 +10057,16 @@ static statement_t *parse_while(void)
 
        PUSH_PARENT(statement);
 
-       expect('(');
+       expect('(', end_error);
        add_anchor_token(')');
        expression_t *const cond = parse_expression();
        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(')');
+       expect(')', end_error);
 
        statement->whiles.body = parse_loop_body(statement);
 
@@ -9727,15 +10092,18 @@ static statement_t *parse_do(void)
        statement->do_while.body = parse_loop_body(statement);
        rem_anchor_token(T_while);
 
-       expect(T_while);
-       expect('(');
+       expect(T_while, end_error);
+       expect('(', end_error);
        add_anchor_token(')');
        expression_t *const cond = parse_expression();
        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(')');
-       expect(';');
+       expect(')', end_error);
+       expect(';', end_error);
 
        POP_PARENT;
        return statement;
@@ -9753,68 +10121,71 @@ static statement_t *parse_for(void)
 
        eat(T_for);
 
-       PUSH_PARENT(statement);
+       expect('(', end_error1);
+       add_anchor_token(')');
 
-       size_t const top = environment_top();
-       scope_push(&statement->fors.scope);
+       PUSH_PARENT(statement);
 
-       expect('(');
-       add_anchor_token(')');
+       size_t const  top       = environment_top();
+       scope_t      *old_scope = scope_push(&statement->fors.scope);
 
-       if (token.type != ';') {
-               if (is_declaration_specifier(&token, false)) {
-                       parse_declaration(record_entity);
-               } else {
-                       add_anchor_token(';');
-                       expression_t *const init = parse_expression();
-                       statement->fors.initialisation = init;
-                       mark_vars_read(init, VAR_ANY);
-                       if (warning.unused_value && !expression_has_effect(init)) {
-                               warningf(&init->base.source_position,
-                                        "initialisation of 'for'-statement has no effect");
-                       }
-                       rem_anchor_token(';');
-                       expect(';');
-               }
+       if (token.type == ';') {
+               next_token();
+       } else if (is_declaration_specifier(&token, false)) {
+               parse_declaration(record_entity, DECL_FLAGS_NONE);
        } else {
-               expect(';');
+               add_anchor_token(';');
+               expression_t *const init = parse_expression();
+               statement->fors.initialisation = init;
+               mark_vars_read(init, ENT_ANY);
+               if (warning.unused_value && !expression_has_effect(init)) {
+                       warningf(&init->base.source_position,
+                                       "initialisation of 'for'-statement has no effect");
+               }
+               rem_anchor_token(';');
+               expect(';', end_error2);
        }
 
        if (token.type != ';') {
                add_anchor_token(';');
                expression_t *const cond = parse_expression();
                statement->fors.condition = cond;
+               /* Â§6.8.5:2    The controlling expression of an iteration statement
+                *             shall have scalar type. */
+               semantic_condition(cond, "condition of 'for'-statement");
                mark_vars_read(cond, NULL);
                rem_anchor_token(';');
        }
-       expect(';');
+       expect(';', end_error2);
        if (token.type != ')') {
                expression_t *const step = parse_expression();
                statement->fors.step = step;
-               mark_vars_read(step, VAR_ANY);
+               mark_vars_read(step, ENT_ANY);
                if (warning.unused_value && !expression_has_effect(step)) {
                        warningf(&step->base.source_position,
                                 "step of 'for'-statement has no effect");
                }
        }
-       expect(')');
+       expect(')', end_error2);
        rem_anchor_token(')');
        statement->fors.body = parse_loop_body(statement);
 
-       assert(scope == &statement->fors.scope);
-       scope_pop();
+       assert(current_scope == &statement->fors.scope);
+       scope_pop(old_scope);
        environment_pop_to(top);
 
        POP_PARENT;
        return statement;
 
-end_error:
+end_error2:
        POP_PARENT;
        rem_anchor_token(')');
-       assert(scope == &statement->fors.scope);
-       scope_pop();
+       assert(current_scope == &statement->fors.scope);
+       scope_pop(old_scope);
        environment_pop_to(top);
+       /* fallthrough */
 
+end_error1:
        return create_invalid_statement();
 }
 
@@ -9831,8 +10202,8 @@ static statement_t *parse_goto(void)
                expression_t *expression = parse_expression();
                mark_vars_read(expression, NULL);
 
-               /* Argh: although documentation say the expression must be of type void *,
-                * gcc excepts anything that can be casted into void * without error */
+               /* Argh: although documentation says the expression must be of type void*,
+                * gcc accepts anything that can be casted into void* without error */
                type_t *type = expression->base.type;
 
                if (type != type_error_type) {
@@ -9863,14 +10234,10 @@ static statement_t *parse_goto(void)
        }
 
        /* remember the goto's in a list for later checking */
-       if (goto_last == NULL) {
-               goto_first = &statement->gotos;
-       } else {
-               goto_last->next = &statement->gotos;
-       }
-       goto_last = &statement->gotos;
+       *goto_anchor = &statement->gotos;
+       goto_anchor  = &statement->gotos.next;
 
-       expect(';');
+       expect(';', end_error);
 
        return statement;
 end_error:
@@ -9889,7 +10256,7 @@ static statement_t *parse_continue(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
 
        eat(T_continue);
-       expect(';');
+       expect(';', end_error);
 
 end_error:
        return statement;
@@ -9907,7 +10274,7 @@ static statement_t *parse_break(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
 
        eat(T_break);
-       expect(';');
+       expect(';', end_error);
 
 end_error:
        return statement;
@@ -9925,7 +10292,7 @@ static statement_t *parse_leave_statement(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
 
        eat(T___leave);
-       expect(';');
+       expect(';', end_error);
 
 end_error:
        return statement;
@@ -9997,7 +10364,7 @@ static statement_t *parse_return(void)
                mark_vars_read(return_value, NULL);
        }
 
-       const type_t *const func_type = current_function->base.type;
+       const type_t *const func_type = skip_typeref(current_function->base.type);
        assert(is_type_function(func_type));
        type_t *const return_type = skip_typeref(func_type->function.return_type);
 
@@ -10032,7 +10399,7 @@ static statement_t *parse_return(void)
        }
        statement->returns.value = return_value;
 
-       expect(';');
+       expect(';', end_error);
 
 end_error:
        return statement;
@@ -10045,18 +10412,19 @@ static statement_t *parse_declaration_statement(void)
 {
        statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
 
-       entity_t *before = scope->last_entity;
-       if (GNU_MODE)
+       entity_t *before = current_scope->last_entity;
+       if (GNU_MODE) {
                parse_external_declaration();
-       else
-               parse_declaration(record_entity);
+       } else {
+               parse_declaration(record_entity, DECL_FLAGS_NONE);
+       }
 
        if (before == NULL) {
-               statement->declaration.declarations_begin = scope->entities;
+               statement->declaration.declarations_begin = current_scope->entities;
        } else {
                statement->declaration.declarations_begin = before->base.next;
        }
-       statement->declaration.declarations_end = scope->last_entity;
+       statement->declaration.declarations_end = current_scope->last_entity;
 
        return statement;
 }
@@ -10070,9 +10438,9 @@ static statement_t *parse_expression_statement(void)
 
        expression_t *const expr         = parse_expression();
        statement->expression.expression = expr;
-       mark_vars_read(expr, VAR_ANY);
+       mark_vars_read(expr, ENT_ANY);
 
-       expect(';');
+       expect(';', end_error);
 
 end_error:
        return statement;
@@ -10098,7 +10466,7 @@ static statement_t *parse_ms_try_statment(void)
 
        if (token.type == T___except) {
                eat(T___except);
-               expect('(');
+               expect('(', end_error);
                add_anchor_token(')');
                expression_t *const expr = parse_expression();
                mark_vars_read(expr, NULL);
@@ -10112,7 +10480,7 @@ static statement_t *parse_ms_try_statment(void)
                }
                statement->ms_try.except_expression = create_implicit_cast(expr, type);
                rem_anchor_token(')');
-               expect(')');
+               expect(')', end_error);
                statement->ms_try.final_statement = parse_compound_statement(false);
        } else if (token.type == T__finally) {
                eat(T___finally);
@@ -10151,15 +10519,15 @@ static statement_t *parse_local_label_declaration(void)
                        goto end_error;
                }
                symbol_t *symbol = token.v.symbol;
-               entity_t *entity = get_entity(symbol, NAMESPACE_LOCAL_LABEL);
-               if (entity != NULL && entity->base.parent_scope == scope) {
+               entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
+               if (entity != NULL && entity->base.parent_scope == current_scope) {
                        errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)",
                               symbol, &entity->base.source_position);
                } else {
                        entity = allocate_entity_zero(ENTITY_LOCAL_LABEL);
 
-                       entity->base.parent_scope    = scope;
-                       entity->base.namespc         = NAMESPACE_LOCAL_LABEL;
+                       entity->base.parent_scope    = current_scope;
+                       entity->base.namespc         = NAMESPACE_LABEL;
                        entity->base.source_position = token.source_position;
                        entity->base.symbol          = symbol;
 
@@ -10169,7 +10537,7 @@ static statement_t *parse_local_label_declaration(void)
                        if (begin == NULL)
                                begin = entity;
 
-                       local_label_push(entity);
+                       environment_push(entity);
                }
                next_token();
 
@@ -10184,6 +10552,55 @@ end_error:
        return statement;
 }
 
+static void parse_namespace_definition(void)
+{
+       eat(T_namespace);
+
+       entity_t *entity = NULL;
+       symbol_t *symbol = NULL;
+
+       if (token.type == T_IDENTIFIER) {
+               symbol = token.v.symbol;
+               next_token();
+
+               entity = get_entity(symbol, NAMESPACE_NORMAL);
+               if (entity != NULL && entity->kind != ENTITY_NAMESPACE
+                               && entity->base.parent_scope == current_scope) {
+                       error_redefined_as_different_kind(&token.source_position,
+                                                         entity, ENTITY_NAMESPACE);
+                       entity = NULL;
+               }
+       }
+
+       if (entity == NULL) {
+               entity                       = allocate_entity_zero(ENTITY_NAMESPACE);
+               entity->base.symbol          = symbol;
+               entity->base.source_position = token.source_position;
+               entity->base.namespc         = NAMESPACE_NORMAL;
+               entity->base.parent_scope    = current_scope;
+       }
+
+       if (token.type == '=') {
+               /* TODO: parse namespace alias */
+               panic("namespace alias definition not supported yet");
+       }
+
+       environment_push(entity);
+       append_entity(current_scope, entity);
+
+       size_t const  top       = environment_top();
+       scope_t      *old_scope = scope_push(&entity->namespacee.members);
+
+       expect('{', end_error);
+       parse_externals();
+       expect('}', end_error);
+
+end_error:
+       assert(current_scope == &entity->namespacee.members);
+       scope_pop(old_scope);
+       environment_pop_to(top);
+}
+
 /**
  * Parse a statement.
  * There's also parse_statement() which additionally checks for
@@ -10208,6 +10625,7 @@ static statement_t *intern_parse_statement(void)
                         * declaration types, so we guess a bit here to improve robustness
                         * for incorrect programs */
                        switch (la1_type) {
+                       case '&':
                        case '*':
                                if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL)
                                        goto expression_statment;
@@ -10235,7 +10653,7 @@ expression_statment:
                } while (token.type == T___extension__);
                bool old_gcc_extension = in_gcc_extension;
                in_gcc_extension       = true;
-               statement = parse_statement();
+               statement = intern_parse_statement();
                in_gcc_extension = old_gcc_extension;
                break;
 
@@ -10247,22 +10665,22 @@ expression_statment:
                statement = parse_local_label_declaration();
                break;
 
-       case ';':        statement = parse_empty_statement();         break;
-       case '{':        statement = parse_compound_statement(false); break;
-       case T___leave:  statement = parse_leave_statement();         break;
-       case T___try:    statement = parse_ms_try_statment();         break;
-       case T_asm:      statement = parse_asm_statement();           break;
-       case T_break:    statement = parse_break();                   break;
-       case T_case:     statement = parse_case_statement();          break;
-       case T_continue: statement = parse_continue();                break;
-       case T_default:  statement = parse_default_statement();       break;
-       case T_do:       statement = parse_do();                      break;
-       case T_for:      statement = parse_for();                     break;
-       case T_goto:     statement = parse_goto();                    break;
-       case T_if:       statement = parse_if();                      break;
-       case T_return:   statement = parse_return();                  break;
-       case T_switch:   statement = parse_switch();                  break;
-       case T_while:    statement = parse_while();                   break;
+       case ';':         statement = parse_empty_statement();         break;
+       case '{':         statement = parse_compound_statement(false); break;
+       case T___leave:   statement = parse_leave_statement();         break;
+       case T___try:     statement = parse_ms_try_statment();         break;
+       case T_asm:       statement = parse_asm_statement();           break;
+       case T_break:     statement = parse_break();                   break;
+       case T_case:      statement = parse_case_statement();          break;
+       case T_continue:  statement = parse_continue();                break;
+       case T_default:   statement = parse_default_statement();       break;
+       case T_do:        statement = parse_do();                      break;
+       case T_for:       statement = parse_for();                     break;
+       case T_goto:      statement = parse_goto();                    break;
+       case T_if:        statement = parse_if();                      break;
+       case T_return:    statement = parse_return();                  break;
+       case T_switch:    statement = parse_switch();                  break;
+       case T_while:     statement = parse_while();                   break;
 
        EXPRESSION_START
                statement = parse_expression_statement();
@@ -10315,10 +10733,97 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
 
        eat('{');
        add_anchor_token('}');
+       /* tokens, which can start a statement */
+       /* TODO MS, __builtin_FOO */
+       add_anchor_token('!');
+       add_anchor_token('&');
+       add_anchor_token('(');
+       add_anchor_token('*');
+       add_anchor_token('+');
+       add_anchor_token('-');
+       add_anchor_token('{');
+       add_anchor_token('~');
+       add_anchor_token(T_CHARACTER_CONSTANT);
+       add_anchor_token(T_COLONCOLON);
+       add_anchor_token(T_FLOATINGPOINT);
+       add_anchor_token(T_IDENTIFIER);
+       add_anchor_token(T_INTEGER);
+       add_anchor_token(T_MINUSMINUS);
+       add_anchor_token(T_PLUSPLUS);
+       add_anchor_token(T_STRING_LITERAL);
+       add_anchor_token(T_WIDE_CHARACTER_CONSTANT);
+       add_anchor_token(T_WIDE_STRING_LITERAL);
+       add_anchor_token(T__Bool);
+       add_anchor_token(T__Complex);
+       add_anchor_token(T__Imaginary);
+       add_anchor_token(T___FUNCTION__);
+       add_anchor_token(T___PRETTY_FUNCTION__);
+       add_anchor_token(T___alignof__);
+       add_anchor_token(T___attribute__);
+       add_anchor_token(T___builtin_va_start);
+       add_anchor_token(T___extension__);
+       add_anchor_token(T___func__);
+       add_anchor_token(T___imag__);
+       add_anchor_token(T___label__);
+       add_anchor_token(T___real__);
+       add_anchor_token(T___thread);
+       add_anchor_token(T_asm);
+       add_anchor_token(T_auto);
+       add_anchor_token(T_bool);
+       add_anchor_token(T_break);
+       add_anchor_token(T_case);
+       add_anchor_token(T_char);
+       add_anchor_token(T_class);
+       add_anchor_token(T_const);
+       add_anchor_token(T_const_cast);
+       add_anchor_token(T_continue);
+       add_anchor_token(T_default);
+       add_anchor_token(T_delete);
+       add_anchor_token(T_double);
+       add_anchor_token(T_do);
+       add_anchor_token(T_dynamic_cast);
+       add_anchor_token(T_enum);
+       add_anchor_token(T_extern);
+       add_anchor_token(T_false);
+       add_anchor_token(T_float);
+       add_anchor_token(T_for);
+       add_anchor_token(T_goto);
+       add_anchor_token(T_if);
+       add_anchor_token(T_inline);
+       add_anchor_token(T_int);
+       add_anchor_token(T_long);
+       add_anchor_token(T_new);
+       add_anchor_token(T_operator);
+       add_anchor_token(T_register);
+       add_anchor_token(T_reinterpret_cast);
+       add_anchor_token(T_restrict);
+       add_anchor_token(T_return);
+       add_anchor_token(T_short);
+       add_anchor_token(T_signed);
+       add_anchor_token(T_sizeof);
+       add_anchor_token(T_static);
+       add_anchor_token(T_static_cast);
+       add_anchor_token(T_struct);
+       add_anchor_token(T_switch);
+       add_anchor_token(T_template);
+       add_anchor_token(T_this);
+       add_anchor_token(T_throw);
+       add_anchor_token(T_true);
+       add_anchor_token(T_try);
+       add_anchor_token(T_typedef);
+       add_anchor_token(T_typeid);
+       add_anchor_token(T_typename);
+       add_anchor_token(T_typeof);
+       add_anchor_token(T_union);
+       add_anchor_token(T_unsigned);
+       add_anchor_token(T_using);
+       add_anchor_token(T_void);
+       add_anchor_token(T_volatile);
+       add_anchor_token(T_wchar_t);
+       add_anchor_token(T_while);
 
-       size_t const top       = environment_top();
-       size_t const top_local = local_label_top();
-       scope_push(&statement->compound.scope);
+       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;
@@ -10357,7 +10862,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        /* look over all statements again to produce no effect warnings */
        if (warning.unused_value) {
                statement_t *sub_statement = statement->compound.statements;
-               for; sub_statement != NULL; sub_statement = sub_statement->base.next) {
+               for (; sub_statement != NULL; sub_statement = sub_statement->base.next) {
                        if (sub_statement->kind != STATEMENT_EXPRESSION)
                                continue;
                        /* don't emit a warning for the last expression in an expression
@@ -10374,43 +10879,101 @@ 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);
+       rem_anchor_token(T_void);
+       rem_anchor_token(T_using);
+       rem_anchor_token(T_unsigned);
+       rem_anchor_token(T_union);
+       rem_anchor_token(T_typeof);
+       rem_anchor_token(T_typename);
+       rem_anchor_token(T_typeid);
+       rem_anchor_token(T_typedef);
+       rem_anchor_token(T_try);
+       rem_anchor_token(T_true);
+       rem_anchor_token(T_throw);
+       rem_anchor_token(T_this);
+       rem_anchor_token(T_template);
+       rem_anchor_token(T_switch);
+       rem_anchor_token(T_struct);
+       rem_anchor_token(T_static_cast);
+       rem_anchor_token(T_static);
+       rem_anchor_token(T_sizeof);
+       rem_anchor_token(T_signed);
+       rem_anchor_token(T_short);
+       rem_anchor_token(T_return);
+       rem_anchor_token(T_restrict);
+       rem_anchor_token(T_reinterpret_cast);
+       rem_anchor_token(T_register);
+       rem_anchor_token(T_operator);
+       rem_anchor_token(T_new);
+       rem_anchor_token(T_long);
+       rem_anchor_token(T_int);
+       rem_anchor_token(T_inline);
+       rem_anchor_token(T_if);
+       rem_anchor_token(T_goto);
+       rem_anchor_token(T_for);
+       rem_anchor_token(T_float);
+       rem_anchor_token(T_false);
+       rem_anchor_token(T_extern);
+       rem_anchor_token(T_enum);
+       rem_anchor_token(T_dynamic_cast);
+       rem_anchor_token(T_do);
+       rem_anchor_token(T_double);
+       rem_anchor_token(T_delete);
+       rem_anchor_token(T_default);
+       rem_anchor_token(T_continue);
+       rem_anchor_token(T_const_cast);
+       rem_anchor_token(T_const);
+       rem_anchor_token(T_class);
+       rem_anchor_token(T_char);
+       rem_anchor_token(T_case);
+       rem_anchor_token(T_break);
+       rem_anchor_token(T_bool);
+       rem_anchor_token(T_auto);
+       rem_anchor_token(T_asm);
+       rem_anchor_token(T___thread);
+       rem_anchor_token(T___real__);
+       rem_anchor_token(T___label__);
+       rem_anchor_token(T___imag__);
+       rem_anchor_token(T___func__);
+       rem_anchor_token(T___extension__);
+       rem_anchor_token(T___builtin_va_start);
+       rem_anchor_token(T___attribute__);
+       rem_anchor_token(T___alignof__);
+       rem_anchor_token(T___PRETTY_FUNCTION__);
+       rem_anchor_token(T___FUNCTION__);
+       rem_anchor_token(T__Imaginary);
+       rem_anchor_token(T__Complex);
+       rem_anchor_token(T__Bool);
+       rem_anchor_token(T_WIDE_STRING_LITERAL);
+       rem_anchor_token(T_WIDE_CHARACTER_CONSTANT);
+       rem_anchor_token(T_STRING_LITERAL);
+       rem_anchor_token(T_PLUSPLUS);
+       rem_anchor_token(T_MINUSMINUS);
+       rem_anchor_token(T_INTEGER);
+       rem_anchor_token(T_IDENTIFIER);
+       rem_anchor_token(T_FLOATINGPOINT);
+       rem_anchor_token(T_COLONCOLON);
+       rem_anchor_token(T_CHARACTER_CONSTANT);
+       rem_anchor_token('~');
+       rem_anchor_token('{');
+       rem_anchor_token('-');
+       rem_anchor_token('+');
+       rem_anchor_token('*');
+       rem_anchor_token('(');
+       rem_anchor_token('&');
+       rem_anchor_token('!');
        rem_anchor_token('}');
-       assert(scope == &statement->compound.scope);
-       scope_pop();
+       assert(current_scope == &statement->compound.scope);
+       scope_pop(old_scope);
        environment_pop_to(top);
-       local_label_pop_to(top_local);
 
        POP_PARENT;
        return statement;
 }
 
-/**
- * Initialize builtin types.
- */
-static void initialize_builtin_types(void)
-{
-       type_intmax_t    = make_global_typedef("__intmax_t__",      type_long_long);
-       type_size_t      = make_global_typedef("__SIZE_TYPE__",     type_unsigned_long);
-       type_ssize_t     = make_global_typedef("__SSIZE_TYPE__",    type_long);
-       type_ptrdiff_t   = make_global_typedef("__PTRDIFF_TYPE__",  type_long);
-       type_uintmax_t   = make_global_typedef("__uintmax_t__",     type_unsigned_long_long);
-       type_uptrdiff_t  = make_global_typedef("__UPTRDIFF_TYPE__", type_unsigned_long);
-       type_wchar_t     = make_global_typedef("__WCHAR_TYPE__",    opt_short_wchar_t ? type_unsigned_short : type_int);
-       type_wint_t      = make_global_typedef("__WINT_TYPE__",     type_int);
-
-       type_intmax_t_ptr  = make_pointer_type(type_intmax_t,  TYPE_QUALIFIER_NONE);
-       type_ptrdiff_t_ptr = make_pointer_type(type_ptrdiff_t, TYPE_QUALIFIER_NONE);
-       type_ssize_t_ptr   = make_pointer_type(type_ssize_t,   TYPE_QUALIFIER_NONE);
-       type_wchar_t_ptr   = make_pointer_type(type_wchar_t,   TYPE_QUALIFIER_NONE);
-
-       /* const version of wchar_t */
-       type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF);
-       type_const_wchar_t->typedeft.typedefe  = type_wchar_t->typedeft.typedefe;
-       type_const_wchar_t->base.qualifiers   |= TYPE_QUALIFIER_CONST;
-
-       type_const_wchar_t_ptr = make_pointer_type(type_const_wchar_t, TYPE_QUALIFIER_NONE);
-}
-
 /**
  * Check for unused global static functions and variables
  */
@@ -10453,30 +11016,109 @@ static void parse_global_asm(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
 
        eat(T_asm);
-       expect('(');
+       expect('(', end_error);
 
        statement->asms.asm_text = parse_string_literals();
        statement->base.next     = unit->global_asm;
        unit->global_asm         = statement;
 
-       expect(')');
-       expect(';');
+       expect(')', end_error);
+       expect(';', end_error);
 
 end_error:;
 }
 
-/**
- * Parse a translation unit.
- */
-static void parse_translation_unit(void)
+static void parse_linkage_specification(void)
+{
+       eat(T_extern);
+       assert(token.type == T_STRING_LITERAL);
+
+       const char *linkage = parse_string_literals().begin;
+
+       linkage_kind_t old_linkage = current_linkage;
+       linkage_kind_t new_linkage;
+       if (strcmp(linkage, "C") == 0) {
+               new_linkage = LINKAGE_C;
+       } else if (strcmp(linkage, "C++") == 0) {
+               new_linkage = LINKAGE_CXX;
+       } else {
+               errorf(HERE, "linkage string \"%s\" not recognized", linkage);
+               new_linkage = LINKAGE_INVALID;
+       }
+       current_linkage = new_linkage;
+
+       if (token.type == '{') {
+               next_token();
+               parse_externals();
+               expect('}', end_error);
+       } else {
+               parse_external();
+       }
+
+end_error:
+       assert(current_linkage == new_linkage);
+       current_linkage = old_linkage;
+}
+
+static void parse_external(void)
+{
+       switch (token.type) {
+               DECLARATION_START_NO_EXTERN
+               case T_IDENTIFIER:
+               case T___extension__:
+               /* tokens below are for implicit int */
+               case '&': /* & x; -> int& x; (and error later, because C++ has no
+                            implicit int) */
+               case '*': /* * x; -> int* x; */
+               case '(': /* (x); -> int (x); */
+                       parse_external_declaration();
+                       return;
+
+               case T_extern:
+                       if (look_ahead(1)->type == T_STRING_LITERAL) {
+                               parse_linkage_specification();
+                       } else {
+                               parse_external_declaration();
+                       }
+                       return;
+
+               case T_asm:
+                       parse_global_asm();
+                       return;
+
+               case T_namespace:
+                       parse_namespace_definition();
+                       return;
+
+               case ';':
+                       if (!strict_mode) {
+                               if (warning.other)
+                                       warningf(HERE, "stray ';' outside of function");
+                               next_token();
+                               return;
+                       }
+                       /* FALLTHROUGH */
+
+               default:
+                       errorf(HERE, "stray %K outside of function", &token);
+                       if (token.type == '(' || token.type == '{' || token.type == '[')
+                               eat_until_matching_token(token.type);
+                       next_token();
+                       return;
+       }
+}
+
+static void parse_externals(void)
 {
+       add_anchor_token('}');
        add_anchor_token(T_EOF);
 
 #ifndef NDEBUG
        unsigned char token_anchor_copy[T_LAST_TOKEN];
        memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
 #endif
-       for (;;) {
+
+       while (token.type != T_EOF && token.type != '}') {
 #ifndef NDEBUG
                bool anchor_leak = false;
                for (int i = 0; i != T_LAST_TOKEN; ++i) {
@@ -10495,37 +11137,30 @@ static void parse_translation_unit(void)
                        abort();
 #endif
 
-               switch (token.type) {
-                       DECLARATION_START
-                       case T_IDENTIFIER:
-                       case T___extension__:
-                               parse_external_declaration();
-                               break;
+               parse_external();
+       }
 
-                       case T_asm:
-                               parse_global_asm();
-                               break;
+       rem_anchor_token(T_EOF);
+       rem_anchor_token('}');
+}
 
-                       case T_EOF:
-                               rem_anchor_token(T_EOF);
-                               return;
+/**
+ * Parse a translation unit.
+ */
+static void parse_translation_unit(void)
+{
+       add_anchor_token(T_EOF);
 
-                       case ';':
-                               if (!strict_mode) {
-                                       if (warning.other)
-                                               warningf(HERE, "stray ';' outside of function");
-                                       next_token();
-                                       break;
-                               }
-                               /* FALLTHROUGH */
+       while (true) {
+               parse_externals();
 
-                       default:
-                               errorf(HERE, "stray %K outside of function", &token);
-                               if (token.type == '(' || token.type == '{' || token.type == '[')
-                                       eat_until_matching_token(token.type);
-                               next_token();
-                               break;
-               }
+               if (token.type == T_EOF)
+                       break;
+
+               errorf(HERE, "stray %K outside of function", &token);
+               if (token.type == '(' || token.type == '{' || token.type == '[')
+                       eat_until_matching_token(token.type);
+               next_token();
        }
 }
 
@@ -10538,7 +11173,6 @@ void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
-       local_label_stack = NEW_ARR_F(stack_entry_t, 0);
        diagnostic_count  = 0;
        error_count       = 0;
        warning_count     = 0;
@@ -10552,17 +11186,14 @@ void start_parsing(void)
        assert(file_scope == NULL);
        file_scope = &unit->scope;
 
-       assert(scope == NULL);
+       assert(current_scope == NULL);
        scope_push(&unit->scope);
-
-       initialize_builtin_types();
 }
 
 translation_unit_t *finish_parsing(void)
 {
-       /* do NOT use scope_pop() here, this will crash, will it by hand */
-       assert(scope == &unit->scope);
-       scope            = NULL;
+       assert(current_scope == &unit->scope);
+       scope_pop(NULL);
 
        assert(file_scope == &unit->scope);
        check_unused_globals();
@@ -10570,20 +11201,56 @@ translation_unit_t *finish_parsing(void)
 
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);
-       DEL_ARR_F(local_label_stack);
 
        translation_unit_t *result = unit;
        unit = NULL;
        return result;
 }
 
+/* GCC allows global arrays without size and assigns them a length of one,
+ * if no different declaration follows */
+static void complete_incomplete_arrays(void)
+{
+       size_t n = ARR_LEN(incomplete_arrays);
+       for (size_t i = 0; i != n; ++i) {
+               declaration_t *const decl      = incomplete_arrays[i];
+               type_t        *const orig_type = decl->type;
+               type_t        *const type      = skip_typeref(orig_type);
+
+               if (!is_type_incomplete(type))
+                       continue;
+
+               if (warning.other) {
+                       warningf(&decl->base.source_position,
+                                       "array '%#T' assumed to have one element",
+                                       orig_type, decl->base.symbol);
+               }
+
+               type_t *const new_type = duplicate_type(type);
+               new_type->array.size_constant     = true;
+               new_type->array.has_implicit_size = true;
+               new_type->array.size              = 1;
+
+               type_t *const result = typehash_insert(new_type);
+               if (type != result)
+                       free_type(type);
+
+               decl->type = result;
+       }
+}
+
 void parse(void)
 {
        lookahead_bufpos = 0;
        for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
                next_token();
        }
+       current_linkage   = c_mode & _CXX ? LINKAGE_CXX : LINKAGE_C;
+       incomplete_arrays = NEW_ARR_F(declaration_t*, 0);
        parse_translation_unit();
+       complete_incomplete_arrays();
+       DEL_ARR_F(incomplete_arrays);
+       incomplete_arrays = NULL;
 }
 
 /**