Improve storage class handling:
[cparser] / parser.c
index 12b9d7d..5e5b419 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -76,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. */
@@ -97,37 +98,46 @@ 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 scope_t            *file_scope        = NULL;
-static scope_t            *current_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 linkage_kind_t      current_linkage   = LINKAGE_INVALID;
-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;
 
 
 #define PUSH_PARENT(stmt)                          \
@@ -179,20 +189,24 @@ 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     \
-       case T_typedef:         \
-       case T_extern:          \
-       case T_static:          \
-       case T_auto:            \
-       case T_register:        \
-       case T___thread:
+#define STORAGE_CLASSES       \
+       STORAGE_CLASSES_NO_EXTERN \
+       case T_extern:
 
 #define STORAGE_CLASSES_NO_EXTERN \
        case T_typedef:         \
@@ -735,15 +749,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.
  */
@@ -794,7 +799,7 @@ 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;
        }
@@ -871,7 +876,7 @@ 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;
@@ -1357,7 +1362,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;
@@ -1382,7 +1387,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;
@@ -1406,7 +1411,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;
@@ -1472,7 +1477,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;
@@ -1501,7 +1506,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;
        }
@@ -1656,7 +1661,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;
                        }
@@ -2345,7 +2350,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);
@@ -2358,7 +2363,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-");
                }
@@ -2455,7 +2460,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;
 
@@ -2476,7 +2481,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;
                                        }
@@ -2945,7 +2950,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__) {
@@ -3005,10 +3010,13 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        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;
@@ -3020,8 +3028,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;
        }
 
@@ -3110,7 +3118,12 @@ static type_t *parse_enum_specifier(void)
 
                parse_enum_entries(type);
                parse_attributes(&attributes);
-       } else if(!entity->enume.complete && !(c_mode & _GNUC)) {
+
+               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 enumes are a GNU extension)",
                       symbol);
        }
@@ -3404,6 +3417,41 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
        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.
@@ -3521,7 +3569,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:                                                        \
@@ -3529,6 +3576,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;
 
@@ -3548,22 +3597,25 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        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;
@@ -3680,6 +3732,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();
@@ -3699,6 +3752,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);
 
@@ -3710,7 +3764,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;
                                        }
@@ -3974,14 +4028,14 @@ 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 */
+       /* §6.9.1:6  The declarations in the declaration list shall contain no
+        *           storage-class specifier other than register and no
+        *           initializations. */
        switch (declaration->declared_storage_class) {
                /* Allowed storage classes */
                case STORAGE_CLASS_NONE:
@@ -3993,18 +4047,13 @@ static void semantic_parameter(declaration_t *declaration)
                        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;
-
+       /* §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 = declaration->type;
        if (is_type_incomplete(skip_typeref(type))) {
-               errorf(pos, "parameter '%#T' is of incomplete type",
-                      orig_type, declaration->base.symbol);
+               errorf(pos, "parameter '%#T' has incomplete type",
+                      type, declaration->base.symbol);
        }
 }
 
@@ -4015,7 +4064,9 @@ 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;
 }
 
@@ -4115,6 +4166,7 @@ end_error:
 typedef enum construct_type_kind_t {
        CONSTRUCT_INVALID,
        CONSTRUCT_POINTER,
+       CONSTRUCT_REFERENCE,
        CONSTRUCT_FUNCTION,
        CONSTRUCT_ARRAY
 } construct_type_kind_t;
@@ -4129,6 +4181,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;
@@ -4152,7 +4210,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('*');
 
@@ -4160,8 +4218,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;
+}
 
-       return (construct_type_t*) pointer;
+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*)reference;
 }
 
 static construct_type_t *parse_array_declarator(void)
@@ -4198,56 +4268,30 @@ static construct_type_t *parse_array_declarator(void)
        expect(']');
 
 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;
 
-       type->function.linkage = current_linkage;
-
-       /* TODO: revive this... once we know exactly how to do it */
-#if 0
-       decl_modifiers_t  modifiers = entity->declaration.modifiers;
+       ftype->linkage = current_linkage;
 
-       unsigned mask = modifiers & (DM_CDECL|DM_STDCALL|DM_FASTCALL|DM_THISCALL);
+       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;
 
-       if (mask & (mask-1)) {
-               const char *first = NULL, *second = NULL;
-
-               /* 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]));
@@ -4276,9 +4320,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('(');
+                               add_anchor_token(')');
+                               parse_microsoft_based(&base_spec);
+                               rem_anchor_token(')');
+                               expect(')');
+                               continue;
+
+                       default:
+                               goto ptr_operator_end;
+               }
 
                if (last == NULL) {
                        first = type;
@@ -4291,9 +4369,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;
 
@@ -4328,7 +4413,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 '(': {
@@ -4336,7 +4421,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 '[':
@@ -4447,11 +4532,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");
@@ -4481,12 +4565,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);
 
@@ -4538,16 +4635,20 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
        return type;
 }
 
+static type_t *automatic_type_conversion(type_t *orig_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);
@@ -4558,16 +4659,62 @@ 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) {
-                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
-               } else if (is_type_function(skip_typeref(type))) {
+               if (flags & DECL_CREATE_COMPOUND_MEMBER) {
+                 entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
+
+                       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) {
+                       /* §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. */
+                       orig_type = automatic_type_conversion(type);
+                       goto create_variable;
+               } 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 {
+create_variable:
                        entity = allocate_entity_zero(ENTITY_VARIABLE);
 
                        entity->variable.get_property_sym = specifiers->get_property_sym;
@@ -4577,17 +4724,37 @@ 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;
@@ -4933,8 +5100,7 @@ error_redeclaration:
                        && 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);
                }
@@ -4994,8 +5160,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;
        }
@@ -5029,9 +5194,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");
                }
@@ -5057,30 +5224,65 @@ static void parse_anonymous_declaration_rest(
        }
 }
 
+static void check_variable_type_complete(entity_t *ent)
+{
+       if (ent->kind != ENTITY_VARIABLE)
+               return;
+
+       /* §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 *type = decl->type;
+       if (!is_type_incomplete(skip_typeref(type)))
+               return;
+
+       errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
+                       type, ent->base.symbol);
+}
+
+
 static void parse_declaration_rest(entity_t *ndeclaration,
                const declaration_specifiers_t *specifiers,
                parsed_declaration_func finished_declaration)
 {
        add_anchor_token(';');
        add_anchor_token(',');
-       while(true) {
+       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, DECL_FLAGS_NONE);
                rem_anchor_token('=');
        }
        expect(';');
 
 end_error:
+       anonymous_entity = NULL;
        rem_anchor_token(';');
        rem_anchor_token(',');
 }
@@ -5121,7 +5323,7 @@ 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);
+               entity_t *entity = parse_declarator(&specifiers, DECL_FLAGS_NONE);
                parse_declaration_rest(entity, &specifiers, finished_declaration);
        }
 }
@@ -5181,7 +5383,7 @@ static void parse_kr_declaration_list(entity_t *entity)
        function_parameter_t *last_parameter = NULL;
 
        entity_t *parameter_declaration = entity->function.parameters.entities;
-       for; parameter_declaration != NULL;
+       for (; parameter_declaration != NULL;
                        parameter_declaration = parameter_declaration->base.next) {
                type_t *parameter_type = parameter_declaration->declaration.type;
                if (parameter_type == NULL) {
@@ -5272,8 +5474,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;
@@ -5288,7 +5488,6 @@ static void check_labels(void)
                        }
                }
        }
-       label_first = label_last = NULL;
 }
 
 static void warn_unused_decl(entity_t *entity, entity_t *end,
@@ -5863,7 +6062,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(';');
@@ -5945,7 +6144,7 @@ static void parse_external_declaration(void)
        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 = current_scope;
                }
@@ -5969,7 +6168,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();
@@ -6025,14 +6229,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;
                }
@@ -6044,11 +6245,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
@@ -6058,10 +6261,6 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
                        }
                        continue;
                }
-
-               if (iter->base.symbol == symbol) {
-                       return iter;
-               }
        }
 
        return NULL;
@@ -6091,7 +6290,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 == ':') {
@@ -6112,7 +6312,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);
@@ -6121,40 +6320,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:
+       anonymous_entity = NULL;
 }
 
 static void parse_compound_type_entries(compound_t *compound)
@@ -6173,9 +6365,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)
@@ -6183,7 +6377,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...
                 */
@@ -6312,10 +6507,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();
@@ -6333,10 +6528,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();
@@ -6909,7 +7104,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) {
@@ -7300,7 +7495,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;
@@ -7440,8 +7635,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;
@@ -7479,6 +7672,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);
@@ -7715,7 +7909,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);
@@ -7746,6 +7940,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 ? ... : ...'.
  *
@@ -7761,13 +8009,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;
@@ -8042,11 +8285,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);
+       }
        }
 }
 
@@ -8096,59 +8344,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;
-       }
-
-       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_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_reference_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;
 }
 
@@ -8224,11 +8423,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,
@@ -8740,25 +8936,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_reference_address_as_bool(left);
-       warn_reference_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;
 }
 
@@ -8998,7 +9179,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();
                }
@@ -9132,8 +9313,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]));
@@ -9216,12 +9397,8 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
 
                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;
@@ -9241,7 +9418,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();
 
@@ -9513,12 +9690,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;
@@ -9541,6 +9714,9 @@ static statement_t *parse_if(void)
        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(')');
@@ -9681,6 +9857,9 @@ static statement_t *parse_while(void)
        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(')');
@@ -9714,6 +9893,9 @@ static statement_t *parse_do(void)
        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(')');
@@ -9743,22 +9925,20 @@ static statement_t *parse_for(void)
        expect('(');
        add_anchor_token(')');
 
-       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);
        } 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(';');
        }
 
@@ -9766,6 +9946,9 @@ static statement_t *parse_for(void)
                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(';');
        }
@@ -9813,8 +9996,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) {
@@ -9845,12 +10028,8 @@ 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(';');
 
@@ -10239,6 +10418,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;
@@ -10266,7 +10446,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;
 
@@ -10387,7 +10567,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