Improve storage class handling:
[cparser] / parser.c
index 7bfe397..5e5b419 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -76,15 +76,15 @@ 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. */
        symbol_t          *get_property_sym;  /**< the name of the get property if set. */
        symbol_t          *put_property_sym;  /**< the name of the put property if set. */
        type_t            *type;
-       variable_t        *based_variable;    /**< Microsoft __based variable. */
 };
 
 /**
@@ -98,6 +98,14 @@ 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. */
@@ -129,6 +137,7 @@ 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 entity_t            *anonymous_entity;
 
 
 #define PUSH_PARENT(stmt)                          \
@@ -180,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:         \
@@ -736,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.
  */
@@ -2946,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__) {
@@ -3008,6 +3012,11 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        if (token.type == '{') {
                parse_compound_type_entries(compound);
                modifiers |= parse_attributes(&attributes);
+
+               if (symbol == NULL) {
+                       assert(anonymous_entity == NULL);
+                       anonymous_entity = (entity_t*)compound;
+               }
        }
 
        compound->modifiers |= modifiers;
@@ -3019,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;
        }
 
@@ -3109,6 +3118,11 @@ static type_t *parse_enum_specifier(void)
 
                parse_enum_entries(type);
                parse_attributes(&attributes);
+
+               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);
@@ -3403,7 +3417,7 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
        return entity;
 }
 
-static void parse_microsoft_based(declaration_specifiers_t *specifiers)
+static void parse_microsoft_based(based_spec_t *based_spec)
 {
        if (token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing __based", T_IDENTIFIER, NULL);
@@ -3418,10 +3432,11 @@ static void parse_microsoft_based(declaration_specifiers_t *specifiers)
        } else {
                variable_t *variable = &entity->variable;
 
-               if (specifiers->based_variable != NULL) {
+               if (based_spec->base_variable != NULL) {
                        errorf(HERE, "__based type qualifier specified more than once");
                }
-               specifiers->based_variable = variable;
+               based_spec->source_position = token.source_position;
+               based_spec->base_variable   = variable;
 
                type_t *const type = variable->base.type;
 
@@ -3554,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:                                                        \
@@ -3562,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;
 
@@ -3580,32 +3596,26 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        expect(')');
                        break;
 
-               case T__based:
-                       next_token();
-                       expect('(');
-                       add_anchor_token(')');
-                       parse_microsoft_based(specifiers);
-                       rem_anchor_token(')');
-                       expect(')');
-                       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;
@@ -3722,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();
@@ -3741,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);
 
@@ -3752,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;
                                        }
@@ -4016,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:
@@ -4035,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);
        }
 }
 
@@ -4057,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;
 }
 
@@ -4157,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;
@@ -4171,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;
@@ -4194,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('*');
 
@@ -4202,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 (construct_type_t*) pointer;
+       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*)reference;
 }
 
 static construct_type_t *parse_array_declarator(void)
@@ -4240,7 +4268,7 @@ 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,
@@ -4292,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;
@@ -4307,6 +4369,11 @@ 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) {
                modifiers      |= env->modifiers;
@@ -4465,8 +4532,7 @@ static void parse_declaration_attributes(entity_t *entity)
        }
 }
 
-static type_t *construct_declarator_type(construct_type_t *construct_list,
-                                         type_t *type, variable_t *variable)
+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) {
@@ -4499,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_based_pointer_type(type, parsed_pointer->type_qualifiers, variable);
+                       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);
 
@@ -4556,17 +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, specifiers->based_variable);
+       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);
@@ -4577,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;
@@ -4596,16 +4724,36 @@ 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.type              = orig_type;
                entity->declaration.modifiers         = env.modifiers;
                entity->declaration.deprecated_string = specifiers->deprecated_string;
 
@@ -4628,7 +4776,7 @@ static type_t *parse_abstract_declarator(type_t *base_type)
 {
        construct_type_t *construct_type = parse_inner_declarator(NULL, 1);
 
-       type_t *result = construct_declarator_type(construct_type, base_type, NULL);
+       type_t *result = construct_declarator_type(construct_type, base_type);
        if (construct_type != NULL) {
                obstack_free(&temp_obst, construct_type);
        }
@@ -4952,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);
                }
@@ -5013,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;
        }
@@ -5048,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");
                }
@@ -5076,6 +5224,26 @@ 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)
@@ -5087,19 +5255,34 @@ static void parse_declaration_rest(entity_t *ndeclaration,
 
                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(',');
 }
@@ -5140,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);
        }
 }
@@ -5879,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(';');
@@ -6107,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 == ':') {
@@ -6162,7 +6346,7 @@ static void parse_compound_declarators(compound_t *compound,
        expect(';');
 
 end_error:
-       ;
+       anonymous_entity = NULL;
 }
 
 static void parse_compound_type_entries(compound_t *compound)
@@ -6193,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...
                 */
@@ -7797,6 +7982,18 @@ static void warn_reference_address_as_bool(expression_t const* expr)
        }
 }
 
+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 ? ... : ...'.
  *
@@ -7809,18 +8006,11 @@ static expression_t *parse_conditional_expression(expression_t *expression)
        conditional_expression_t *conditional = &result->conditional;
        conditional->condition                = expression;
 
-       warn_reference_address_as_bool(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;
@@ -8095,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);
+       }
        }
 }
 
@@ -8151,15 +8346,8 @@ static void semantic_unexpr_plus(unary_expression_t *expression)
 
 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;
 }
 
@@ -8748,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;
 }
 
@@ -9541,7 +9714,9 @@ static statement_t *parse_if(void)
        add_anchor_token(')');
        expression_t *const expr = parse_expression();
        statement->ifs.condition = expr;
-       warn_reference_address_as_bool(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(')');
@@ -9682,7 +9857,9 @@ static statement_t *parse_while(void)
        add_anchor_token(')');
        expression_t *const cond = parse_expression();
        statement->whiles.condition = cond;
-       warn_reference_address_as_bool(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(')');
@@ -9716,7 +9893,9 @@ static statement_t *parse_do(void)
        add_anchor_token(')');
        expression_t *const cond = parse_expression();
        statement->do_while.condition = cond;
-       warn_reference_address_as_bool(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(')');
@@ -9746,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(';');
        }
 
@@ -9769,7 +9946,9 @@ static statement_t *parse_for(void)
                add_anchor_token(';');
                expression_t *const cond = parse_expression();
                statement->fors.condition = cond;
-               warn_reference_address_as_bool(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(';');
        }
@@ -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;