Do not generate warnings for implicit declarations in record_entity().
[cparser] / parser.c
index 93fff4b..d9397d9 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -108,6 +108,7 @@ static bool                 in_gcc_extension  = false;
 static struct obstack       temp_obst;
 static entity_t            *anonymous_entity;
 static declaration_t      **incomplete_arrays;
+static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 
 
 #define PUSH_PARENT(stmt)                          \
@@ -214,10 +215,6 @@ static void semantic_comparison(binary_expression_t *expression);
        TYPE_QUALIFIERS                 \
        TYPE_SPECIFIERS
 
-#define TYPENAME_START      \
-       TYPE_QUALIFIERS         \
-       TYPE_SPECIFIERS
-
 #define EXPRESSION_START              \
        case '!':                         \
        case '&':                         \
@@ -292,7 +289,7 @@ static size_t get_statement_struct_size(statement_kind_t kind)
                [STATEMENT_MS_TRY]      = sizeof(ms_try_statement_t),
                [STATEMENT_LEAVE]       = sizeof(leave_statement_t)
        };
-       assert(kind < lengthof(sizes));
+       assert((size_t)kind < lengthof(sizes));
        assert(sizes[kind] != 0);
        return sizes[kind];
 }
@@ -308,6 +305,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_INVALID]                    = sizeof(expression_base_t),
                [EXPR_REFERENCE]                  = sizeof(reference_expression_t),
                [EXPR_REFERENCE_ENUM_VALUE]       = sizeof(reference_expression_t),
+               [EXPR_LITERAL_BOOLEAN]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_INTEGER]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_INTEGER_OCTAL]      = sizeof(literal_expression_t),
                [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t),
@@ -343,7 +341,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
        if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) {
                return sizes[EXPR_BINARY_FIRST];
        }
-       assert(kind < lengthof(sizes));
+       assert((size_t)kind < lengthof(sizes));
        assert(sizes[kind] != 0);
        return sizes[kind];
 }
@@ -429,7 +427,7 @@ static size_t get_initializer_size(initializer_kind_t kind)
                [INITIALIZER_LIST]        = sizeof(initializer_list_t),
                [INITIALIZER_DESIGNATOR]  = sizeof(initializer_designator_t)
        };
-       assert(kind < lengthof(sizes));
+       assert((size_t)kind < lengthof(sizes));
        assert(sizes[kind] != 0);
        return sizes[kind];
 }
@@ -705,7 +703,7 @@ static entity_t *get_entity(const symbol_t *const symbol,
        assert(namespc != NAMESPACE_INVALID);
        entity_t *entity = symbol->entity;
        for (; entity != NULL; entity = entity->base.symbol_next) {
-               if (entity->base.namespc == namespc)
+               if ((namespace_tag_t)entity->base.namespc == namespc)
                        return entity;
        }
 
@@ -718,7 +716,7 @@ static entity_t *get_tag(symbol_t const *const symbol,
                          entity_kind_tag_t const kind)
 {
        entity_t *entity = get_entity(symbol, NAMESPACE_TAG);
-       if (entity != NULL && entity->kind != kind) {
+       if (entity != NULL && (entity_kind_tag_t)entity->kind != kind) {
                errorf(HERE,
                                "'%Y' defined as wrong kind of tag (previous definition %P)",
                                symbol, &entity->base.source_position);
@@ -1267,24 +1265,25 @@ static attribute_t *parse_attribute_gnu_single(void)
                return NULL;
        }
 
-       const char *name = symbol->string;
-       next_token();
+       attribute_kind_t  kind;
+       char const *const name = symbol->string;
+       for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) {
+               if (kind > ATTRIBUTE_GNU_LAST) {
+                       if (warning.attribute) {
+                               warningf(HERE, "unknown attribute '%s' ignored", name);
+                       }
+                       /* TODO: we should still save the attribute in the list... */
+                       kind = ATTRIBUTE_UNKNOWN;
+                       break;
+               }
 
-       attribute_kind_t kind;
-       for (kind = ATTRIBUTE_GNU_FIRST; kind <= ATTRIBUTE_GNU_LAST; ++kind) {
                const char *attribute_name = get_attribute_name(kind);
                if (attribute_name != NULL
                                && strcmp_underscore(attribute_name, name) == 0)
                        break;
        }
 
-       if (kind >= ATTRIBUTE_GNU_LAST) {
-               if (warning.attribute) {
-                       warningf(HERE, "unknown attribute '%s' ignored", name);
-               }
-               /* TODO: we should still save the attribute in the list... */
-               kind = ATTRIBUTE_UNKNOWN;
-       }
+       next_token();
 
        attribute_t *attribute = allocate_attribute_zero(kind);
 
@@ -1360,10 +1359,10 @@ static attribute_t *parse_attributes(attribute_t *first)
                        break;
 
                case T___thiscall:
-                       next_token();
                        /* TODO record modifier */
                        if (warning.other)
                                warningf(HERE, "Ignoring declaration modifier %K", &token);
+                       eat(T___thiscall);
                        attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL);
                        break;
 
@@ -1733,13 +1732,12 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
 }
 
 /**
- * Checks if a given expression can be used as an constant initializer.
+ * Checks if a given expression can be used as a constant initializer.
  */
 static bool is_initializer_constant(const expression_t *expression)
 {
-       return
-               is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
-               is_address_constant(expression)    != EXPR_CLASS_VARIABLE;
+       return is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+              is_linker_constant(expression)     != EXPR_CLASS_VARIABLE;
 }
 
 /**
@@ -1752,12 +1750,13 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 {
        /* there might be extra {} hierarchies */
        int braces = 0;
-       if (next_if('{')) {
+       if (token.type == '{') {
                if (warning.other)
                        warningf(HERE, "extra curly braces around scalar initializer");
                do {
+                       eat('{');
                        ++braces;
-               } while (next_if('{'));
+               } while (token.type == '{');
        }
 
        expression_t *expression = parse_assignment_expression();
@@ -2154,7 +2153,6 @@ finish_designator:
                        if (type != NULL && is_type_scalar(type)) {
                                sub = parse_scalar_initializer(type, env->must_be_constant);
                        } else {
-                               eat('{');
                                if (type == NULL) {
                                        if (env->entity != NULL) {
                                                errorf(HERE,
@@ -2163,8 +2161,11 @@ finish_designator:
                                        } else {
                                                errorf(HERE, "extra brace group at end of initializer");
                                        }
-                               } else
+                                       eat('{');
+                               } else {
+                                       eat('{');
                                        descend_into_subtype(path);
+                               }
 
                                add_anchor_token('}');
                                sub = parse_sub_initializer(path, orig_type, top_path_level+1,
@@ -2196,10 +2197,19 @@ finish_designator:
                                        goto error_parse_next;
                                type_t *const outer_type_skip = skip_typeref(outer_type);
                                if (is_type_compound(outer_type_skip) &&
-                                   !outer_type_skip->compound.compound->complete) {
+                                               !outer_type_skip->compound.compound->complete) {
                                        goto error_parse_next;
                                }
-                               goto error_excess;
+
+                               if (warning.other) {
+                                       source_position_t const* const pos = &expression->base.source_position;
+                                       if (env->entity != NULL) {
+                                               warningf(pos, "excess elements in initializer for '%Y'", env->entity->base.symbol);
+                                       } else {
+                                               warningf(pos, "excess elements in initializer");
+                                       }
+                               }
+                               goto error_parse_next;
                        }
 
                        /* handle { "string" } special case */
@@ -2251,20 +2261,8 @@ finish_designator:
                                path->max_index = index;
                }
 
-               if (type != NULL) {
-                       /* append to initializers list */
-                       ARR_APP1(initializer_t*, initializers, sub);
-               } else {
-error_excess:
-                       if (warning.other) {
-                               if (env->entity != NULL) {
-                                       warningf(HERE, "excess elements in initializer for '%Y'",
-                                                env->entity->base.symbol);
-                               } else {
-                                       warningf(HERE, "excess elements in initializer");
-                               }
-                       }
-               }
+               /* append to initializers list */
+               ARR_APP1(initializer_t*, initializers, sub);
 
 error_parse_next:
                if (token.type == '}') {
@@ -2348,6 +2346,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                DEL_ARR_F(path.path);
 
                expect('}', end_error);
+end_error:;
        } else {
                /* parse_scalar_initializer() also works in this case: we simply
                 * have an expression without {} around it */
@@ -2393,8 +2392,6 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
        }
 
        return result;
-end_error:
-       return NULL;
 }
 
 static void append_entity(scope_t *scope, entity_t *entity)
@@ -2411,6 +2408,7 @@ static void append_entity(scope_t *scope, entity_t *entity)
 
 static compound_t *parse_compound_type_specifier(bool is_struct)
 {
+       source_position_t const pos = *HERE;
        eat(is_struct ? T_struct : T_union);
 
        symbol_t    *symbol     = NULL;
@@ -2425,9 +2423,9 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        if (token.type == T_IDENTIFIER) {
                /* the compound has a name, check if we have seen it already */
                symbol = token.symbol;
+               entity = get_tag(symbol, kind);
                next_token();
 
-               entity = get_tag(symbol, kind);
                if (entity != NULL) {
                        if (entity->base.parent_scope != current_scope &&
                            (token.type == '{' || token.type == ';')) {
@@ -2435,33 +2433,25 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                                 * existing definition in outer scope */
                                entity = NULL;
                        } else if (entity->compound.complete && token.type == '{') {
-                               assert(symbol != NULL);
-                               errorf(HERE, "multiple definitions of '%s %Y' (previous definition %P)",
-                                      is_struct ? "struct" : "union", symbol,
-                                      &entity->base.source_position);
+                               source_position_t const *const ppos = &entity->base.source_position;
+                               errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                                /* clear members in the hope to avoid further errors */
                                entity->compound.members.entities = NULL;
                        }
                }
        } else if (token.type != '{') {
-               if (is_struct) {
-                       parse_error_expected("while parsing struct type specifier",
-                                            T_IDENTIFIER, '{', NULL);
-               } else {
-                       parse_error_expected("while parsing union type specifier",
-                                            T_IDENTIFIER, '{', NULL);
-               }
+               char const *const msg =
+                       is_struct ? "while parsing struct type specifier" :
+                                   "while parsing union type specifier";
+               parse_error_expected(msg, T_IDENTIFIER, '{', NULL);
 
                return NULL;
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(kind);
-
+               entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol);
                entity->compound.alignment   = 1;
-               entity->base.namespc         = NAMESPACE_TAG;
-               entity->base.source_position = token.source_position;
-               entity->base.symbol          = symbol;
+               entity->base.source_position = pos;
                entity->base.parent_scope    = current_scope;
                if (symbol != NULL) {
                        environment_push(entity);
@@ -2505,10 +2495,8 @@ static void parse_enum_entries(type_t *const enum_type)
                        return;
                }
 
-               entity_t *entity             = allocate_entity_zero(ENTITY_ENUM_VALUE);
+               entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, token.symbol);
                entity->enum_value.enum_type = enum_type;
-               entity->base.namespc         = NAMESPACE_NORMAL;
-               entity->base.symbol          = token.symbol;
                entity->base.source_position = token.source_position;
                next_token();
 
@@ -2533,16 +2521,17 @@ end_error:
 
 static type_t *parse_enum_specifier(void)
 {
-       entity_t *entity;
-       symbol_t *symbol;
+       source_position_t const pos = *HERE;
+       entity_t               *entity;
+       symbol_t               *symbol;
 
        eat(T_enum);
        switch (token.type) {
                case T_IDENTIFIER:
                        symbol = token.symbol;
+                       entity = get_tag(symbol, ENTITY_ENUM);
                        next_token();
 
-                       entity = get_tag(symbol, ENTITY_ENUM);
                        if (entity != NULL) {
                                if (entity->base.parent_scope != current_scope &&
                                                (token.type == '{' || token.type == ';')) {
@@ -2550,8 +2539,8 @@ static type_t *parse_enum_specifier(void)
                                         * existing definition in outer scope */
                                        entity = NULL;
                                } else if (entity->enume.complete && token.type == '{') {
-                                       errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
-                                                       symbol, &entity->base.source_position);
+                                       source_position_t const *const ppos = &entity->base.source_position;
+                                       errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                                }
                        }
                        break;
@@ -2568,10 +2557,8 @@ static type_t *parse_enum_specifier(void)
        }
 
        if (entity == NULL) {
-               entity                       = allocate_entity_zero(ENTITY_ENUM);
-               entity->base.namespc         = NAMESPACE_TAG;
-               entity->base.source_position = token.source_position;
-               entity->base.symbol          = symbol;
+               entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol);
+               entity->base.source_position = pos;
                entity->base.parent_scope    = current_scope;
        }
 
@@ -2595,8 +2582,7 @@ static type_t *parse_enum_specifier(void)
                        anonymous_entity = entity;
                }
        } else if (!entity->enume.complete && !(c_mode & _GNUC)) {
-               errorf(HERE, "'enum %Y' used before definition (incomplete enums are a GNU extension)",
-                      symbol);
+               errorf(HERE, "'%T' used before definition (incomplete enums are a GNU extension)", type);
        }
 
        return type;
@@ -2633,7 +2619,7 @@ static type_t *parse_typeof(void)
        switch (token.type) {
        case T_IDENTIFIER:
                if (is_typedef_symbol(token.symbol)) {
-       TYPENAME_START
+       DECLARATION_START
                        type = parse_typename();
                } else {
        default:
@@ -2705,28 +2691,25 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
                        goto end_error;
                }
 
-               bool is_put;
-               symbol_t *symbol = token.symbol;
-               next_token();
+               symbol_t **prop;
+               symbol_t  *symbol = token.symbol;
                if (strcmp(symbol->string, "put") == 0) {
-                       is_put = true;
+                       prop = &property->put_symbol;
                } else if (strcmp(symbol->string, "get") == 0) {
-                       is_put = false;
+                       prop = &property->get_symbol;
                } else {
                        errorf(HERE, "expected put or get in property declspec");
-                       goto end_error;
+                       prop = NULL;
                }
+               eat(T_IDENTIFIER);
                expect('=', end_error);
                if (token.type != T_IDENTIFIER) {
                        parse_error_expected("while parsing property declspec",
                                             T_IDENTIFIER, NULL);
                        goto end_error;
                }
-               if (is_put) {
-                       property->put_symbol = token.symbol;
-               } else {
-                       property->get_symbol = token.symbol;
-               }
+               if (prop != NULL)
+                       *prop = token.symbol;
                next_token();
        } while (next_if(','));
 
@@ -2745,7 +2728,6 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
                kind = ATTRIBUTE_MS_RESTRICT;
        } else if (token.type == T_IDENTIFIER) {
                const char *name = token.symbol->string;
-               next_token();
                for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
                     ++k) {
                        const char *attribute_name = get_attribute_name(k);
@@ -2758,6 +2740,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
                if (kind == ATTRIBUTE_UNKNOWN && warning.attribute) {
                        warningf(HERE, "unknown __declspec '%s' ignored", name);
                }
+               eat(T_IDENTIFIER);
        } else {
                parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL);
                return NULL;
@@ -2812,10 +2795,8 @@ end_error:
 
 static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
 {
-       entity_t *entity             = allocate_entity_zero(kind);
-       entity->base.namespc         = NAMESPACE_NORMAL;
+       entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol);
        entity->base.source_position = *HERE;
-       entity->base.symbol          = symbol;
        if (is_declaration(entity)) {
                entity->declaration.type     = type_error_type;
                entity->declaration.implicit = true;
@@ -2837,6 +2818,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
        bool               saw_error         = false;
        bool               old_gcc_extension = in_gcc_extension;
 
+       memset(specifiers, 0, sizeof(*specifiers));
        specifiers->source_position = token.source_position;
 
        while (true) {
@@ -2965,8 +2947,10 @@ wrong_thread_storage_class:
                        break;
 
 #define CHECK_DOUBLE_TYPE()        \
+                       do { \
                        if ( type != NULL)     \
-                               errorf(HERE, "multiple data types in declaration specifiers");
+                               errorf(HERE, "multiple data types in declaration specifiers"); \
+                       } while(0)
 
                case T_struct:
                        CHECK_DOUBLE_TYPE();
@@ -3202,32 +3186,33 @@ warn_about_long_long:
                case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
                        atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
                        break;
-               default:
+               default: {
                        /* invalid specifier combination, give an error message */
+                       source_position_t const* const pos = &specifiers->source_position;
                        if (type_specifiers == 0) {
-                               if (saw_error)
-                                       goto end_error;
-
-                               /* ISO/IEC 14882:1998(E) Â§C.1.5:4 */
-                               if (!(c_mode & _CXX) && !strict_mode) {
-                                       if (warning.implicit_int) {
-                                               warningf(HERE, "no type specifiers in declaration, using 'int'");
+                               if (!saw_error) {
+                                       /* ISO/IEC 14882:1998(E) Â§C.1.5:4 */
+                                       if (!(c_mode & _CXX) && !strict_mode) {
+                                               if (warning.implicit_int) {
+                                                       warningf(pos, "no type specifiers in declaration, using 'int'");
+                                               }
+                                               atomic_type = ATOMIC_TYPE_INT;
+                                               break;
+                                       } else {
+                                               errorf(pos, "no type specifiers given in declaration");
                                        }
-                                       atomic_type = ATOMIC_TYPE_INT;
-                                       break;
-                               } else {
-                                       errorf(HERE, "no type specifiers given in declaration");
                                }
                        } else if ((type_specifiers & SPECIFIER_SIGNED) &&
                                  (type_specifiers & SPECIFIER_UNSIGNED)) {
-                               errorf(HERE, "signed and unsigned specifiers given");
+                               errorf(pos, "signed and unsigned specifiers given");
                        } else if (type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) {
-                               errorf(HERE, "only integer types can be signed or unsigned");
+                               errorf(pos, "only integer types can be signed or unsigned");
                        } else {
-                               errorf(HERE, "multiple datatypes in declaration");
+                               errorf(pos, "multiple datatypes in declaration");
                        }
                        goto end_error;
                }
+               }
 
                if (type_specifiers & SPECIFIER_COMPLEX) {
                        type                = allocate_type_zero(TYPE_COMPLEX);
@@ -3241,7 +3226,7 @@ warn_about_long_long:
                }
                newtype = true;
        } else if (type_specifiers != 0) {
-               errorf(HERE, "multiple datatypes in declaration");
+               errorf(&specifiers->source_position, "multiple datatypes in declaration");
        }
 
        /* FIXME: check type qualifiers here */
@@ -3291,10 +3276,8 @@ static type_qualifiers_t parse_type_qualifiers(void)
 static void parse_identifier_list(scope_t *scope)
 {
        do {
-               entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER);
+               entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.symbol);
                entity->base.source_position = token.source_position;
-               entity->base.namespc         = NAMESPACE_NORMAL;
-               entity->base.symbol          = token.symbol;
                /* a K&R parameter has no type, yet */
                next_token();
 
@@ -3306,8 +3289,6 @@ static void parse_identifier_list(scope_t *scope)
 static entity_t *parse_parameter(void)
 {
        declaration_specifiers_t specifiers;
-       memset(&specifiers, 0, sizeof(specifiers));
-
        parse_declaration_specifiers(&specifiers);
 
        entity_t *entity = parse_declarator(&specifiers,
@@ -3326,9 +3307,7 @@ static void semantic_parameter_incomplete(const entity_t *entity)
         *             incomplete type. */
        type_t *type = skip_typeref(entity->declaration.type);
        if (is_type_incomplete(type)) {
-               errorf(&entity->base.source_position,
-                               "parameter '%#T' has incomplete type",
-                               entity->declaration.type, entity->base.symbol);
+               errorf(&entity->base.source_position, "'%N' has incomplete type", entity);
        }
 }
 
@@ -3545,7 +3524,7 @@ static construct_type_t *parse_array_declarator(void)
        }
 
        if (is_static && size == NULL)
-               errorf(HERE, "static array parameters require a size");
+               errorf(&array->base.pos, "static array parameters require a size");
 
        rem_anchor_token(']');
        expect(']', end_error);
@@ -3648,7 +3627,6 @@ ptr_operator_end: ;
                                        /* Function declarator. */
                                        if (!env->may_be_abstract) {
                                                errorf(HERE, "function declarator must have a name");
-                                               goto error_out;
                                        }
                                } else {
                        case '&':
@@ -3676,7 +3654,6 @@ ptr_operator_end: ;
                if (env->may_be_abstract)
                        break;
                parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
-error_out:
                eat_until_anchor();
                return NULL;
        }
@@ -3789,30 +3766,28 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                        if (size_expression != NULL) {
                                switch (is_constant_expression(size_expression)) {
-                                       case EXPR_CLASS_CONSTANT: {
-                                               long const size = fold_constant_to_int(size_expression);
-                                               array_type->array.size          = size;
-                                               array_type->array.size_constant = true;
-                                               /* Â§6.7.5.2:1  If the expression is a constant expression, it shall
-                                                * have a value greater than zero. */
-                                               if (size <= 0) {
-                                                       if (size < 0 || !GNU_MODE) {
-                                                               errorf(&size_expression->base.source_position,
-                                                                               "size of array must be greater than zero");
-                                                       } else if (warning.other) {
-                                                               warningf(&size_expression->base.source_position,
-                                                                               "zero length arrays are a GCC extension");
-                                                       }
-                                               }
-                                               break;
+                               case EXPR_CLASS_CONSTANT: {
+                                       long const size = fold_constant_to_int(size_expression);
+                                       array_type->array.size          = size;
+                                       array_type->array.size_constant = true;
+                                       /* Â§6.7.5.2:1  If the expression is a constant expression,
+                                        * it shall have a value greater than zero. */
+                                       if (size < 0) {
+                                               errorf(&size_expression->base.source_position,
+                                                          "size of array must be greater than zero");
+                                       } else if (size == 0 && !GNU_MODE) {
+                                               errorf(&size_expression->base.source_position,
+                                                          "size of array must be greater than zero (zero length arrays are a GCC extension)");
                                        }
+                                       break;
+                               }
 
-                                       case EXPR_CLASS_VARIABLE:
-                                               array_type->array.is_vla = true;
-                                               break;
+                               case EXPR_CLASS_VARIABLE:
+                                       array_type->array.is_vla = true;
+                                       break;
 
-                                       case EXPR_CLASS_ERROR:
-                                               break;
+                               case EXPR_CLASS_ERROR:
+                                       break;
                                }
                        }
 
@@ -3838,7 +3813,7 @@ static type_t *automatic_type_conversion(type_t *orig_type);
 static type_t *semantic_parameter(const source_position_t *pos,
                                   type_t *type,
                                   const declaration_specifiers_t *specifiers,
-                                  symbol_t *symbol)
+                                  entity_t const *const param)
 {
        /* Â§6.7.5.3:7  A declaration of a parameter as ``array of type''
         *             shall be adjusted to ``qualified pointer to type'',
@@ -3849,7 +3824,7 @@ static type_t *semantic_parameter(const source_position_t *pos,
        type = automatic_type_conversion(type);
 
        if (specifiers->is_inline && is_type_valid(type)) {
-               errorf(pos, "parameter '%#T' declared 'inline'", type, symbol);
+               errorf(pos, "'%N' declared 'inline'", param);
        }
 
        /* Â§6.9.1:6  The declarations in the declaration list shall contain
@@ -3859,7 +3834,7 @@ static type_t *semantic_parameter(const source_position_t *pos,
                        specifiers->storage_class != STORAGE_CLASS_NONE   &&
                        specifiers->storage_class != STORAGE_CLASS_REGISTER)
           ) {
-               errorf(pos, "invalid storage class for parameter '%#T'", type, symbol);
+               errorf(pos, "invalid storage class for '%N'", param);
        }
 
        /* delay test for incomplete type, because we might have (void)
@@ -3894,9 +3869,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        entity_t *entity;
        if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
-               entity                       = allocate_entity_zero(ENTITY_TYPEDEF);
-               entity->base.namespc         = NAMESPACE_NORMAL;
-               entity->base.symbol          = env.symbol;
+               entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol);
                entity->base.source_position = env.source_position;
                entity->typedefe.type        = orig_type;
 
@@ -3917,7 +3890,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
        } else {
                /* create a declaration type entity */
                if (flags & DECL_CREATE_COMPOUND_MEMBER) {
-                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
+                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol);
 
                        if (env.symbol != NULL) {
                                if (specifiers->is_inline && is_type_valid(type)) {
@@ -3933,15 +3906,13 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                }
                        }
                } else if (flags & DECL_IS_PARAMETER) {
-                       orig_type = semantic_parameter(&env.source_position, orig_type,
-                                                      specifiers, env.symbol);
-
-                       entity = allocate_entity_zero(ENTITY_PARAMETER);
+                       entity    = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol);
+                       orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
                } else if (is_type_function(type)) {
-                       entity = allocate_entity_zero(ENTITY_FUNCTION);
-
-                       entity->function.is_inline  = specifiers->is_inline;
-                       entity->function.parameters = env.parameters;
+                       entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol);
+                       entity->function.is_inline      = specifiers->is_inline;
+                       entity->function.elf_visibility = default_visibility;
+                       entity->function.parameters     = env.parameters;
 
                        if (env.symbol != NULL) {
                                /* this needs fixes for C++ */
@@ -3952,19 +3923,17 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                                        specifiers->storage_class != STORAGE_CLASS_NONE   &&
                                                        (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
                                                )) {
-                                       errorf(&env.source_position,
-                                                       "invalid storage class for function '%Y'", env.symbol);
+                                       errorf(&env.source_position, "invalid storage class for '%N'", entity);
                                }
                        }
                } else {
-                       entity = allocate_entity_zero(ENTITY_VARIABLE);
-
-                       entity->variable.thread_local = specifiers->thread_local;
+                       entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol);
+                       entity->variable.elf_visibility = default_visibility;
+                       entity->variable.thread_local   = specifiers->thread_local;
 
                        if (env.symbol != NULL) {
                                if (specifiers->is_inline && is_type_valid(type)) {
-                                       errorf(&env.source_position,
-                                                       "variable '%Y' declared 'inline'", env.symbol);
+                                       errorf(&env.source_position, "'%N' declared 'inline'", entity);
                                }
 
                                bool invalid_storage_class = false;
@@ -3981,19 +3950,12 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                        }
                                }
                                if (invalid_storage_class) {
-                                       errorf(&env.source_position,
-                                                       "invalid storage class for variable '%Y'", env.symbol);
+                                       errorf(&env.source_position, "invalid storage class for variable '%N'", entity);
                                }
                        }
                }
 
-               if (env.symbol != NULL) {
-                       entity->base.symbol          = env.symbol;
-                       entity->base.source_position = env.source_position;
-               } else {
-                       entity->base.source_position = specifiers->source_position;
-               }
-               entity->base.namespc           = NAMESPACE_NORMAL;
+               entity->base.source_position   = env.symbol != NULL ? env.source_position : specifiers->source_position;
                entity->declaration.type       = orig_type;
                entity->declaration.alignment  = get_type_alignment(orig_type);
                entity->declaration.modifiers  = env.modifiers;
@@ -4111,9 +4073,9 @@ static bool is_sym_main(const symbol_t *const sym)
 static void error_redefined_as_different_kind(const source_position_t *pos,
                const entity_t *old, entity_kind_t new_kind)
 {
-       errorf(pos, "redeclaration of %s '%Y' as %s (declared %P)",
-              get_entity_kind_name(old->kind), old->base.symbol,
-              get_entity_kind_name(new_kind), &old->base.source_position);
+       char              const *const what = get_entity_kind_name(new_kind);
+       source_position_t const *const ppos = &old->base.source_position;
+       errorf(pos, "redeclaration of '%N' as %s (declared %P)", old, what, ppos);
 }
 
 static bool is_entity_valid(entity_t *const ent)
@@ -4191,10 +4153,10 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                assert(is_type_function(type));
                if (type->function.unspecified_parameters &&
-                               warning.strict_prototypes &&
-                               previous_entity == NULL) {
-                       warningf(pos, "function declaration '%#T' is not a prototype",
-                                        orig_type, symbol);
+                               warning.strict_prototypes             &&
+                   previous_entity == NULL               &&
+                   !entity->declaration.implicit) {
+                       warningf(pos, "function declaration '%#N' is not a prototype", entity);
                }
 
                if (warning.main && current_scope == file_scope
@@ -4203,23 +4165,21 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                }
        }
 
-       if (is_declaration(entity) &&
-                       warning.nested_externs &&
-                       entity->declaration.storage_class == STORAGE_CLASS_EXTERN &&
-                       current_scope != file_scope) {
-               warningf(pos, "nested extern declaration of '%#T'",
-                        entity->declaration.type, symbol);
+       if (is_declaration(entity)                                    &&
+           warning.nested_externs                                    &&
+           entity->declaration.storage_class == STORAGE_CLASS_EXTERN &&
+           current_scope != file_scope                               &&
+           !entity->declaration.implicit) {
+               warningf(pos, "nested extern declaration of '%#N'", entity);
        }
 
        if (previous_entity != NULL) {
+               source_position_t const *const ppos = &previous_entity->base.source_position;
+
                if (previous_entity->base.parent_scope == &current_function->parameters &&
                                previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
                        assert(previous_entity->kind == ENTITY_PARAMETER);
-                       errorf(pos,
-                                       "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
-                                       entity->declaration.type, symbol,
-                                       previous_entity->declaration.type, symbol,
-                                       &previous_entity->base.source_position);
+                       errorf(pos, "declaration of '%N' redeclares the '%N' (declared %P)", entity, previous_entity, ppos);
                        goto finish;
                }
 
@@ -4232,14 +4192,12 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                                goto finish;
                        }
                        if (previous_entity->kind == ENTITY_ENUM_VALUE) {
-                               errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
-                                               symbol, &previous_entity->base.source_position);
+                               errorf(pos, "redeclaration of '%N' (declared %P)", entity, ppos);
                                goto finish;
                        }
                        if (previous_entity->kind == ENTITY_TYPEDEF) {
                                /* TODO: C++ allows this for exactly the same type */
-                               errorf(pos, "redefinition of typedef '%Y' (declared %P)",
-                                               symbol, &previous_entity->base.source_position);
+                               errorf(pos, "redefinition of '%N' (declared %P)", entity, ppos);
                                goto finish;
                        }
 
@@ -4260,16 +4218,11 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                                return previous_entity;
                        }
 
-                       type_t *const orig_type = decl->type;
-                       assert(orig_type != NULL);
-                       type_t *const type      = skip_typeref(orig_type);
+                       type_t *const type      = skip_typeref(decl->type);
                        type_t *const prev_type = skip_typeref(prev_decl->type);
 
                        if (!types_compatible(type, prev_type)) {
-                               errorf(pos,
-                                               "declaration '%#T' is incompatible with '%#T' (declared %P)",
-                                               orig_type, symbol, prev_decl->type, symbol,
-                                               &previous_entity->base.source_position);
+                               errorf(pos, "declaration '%#N' is incompatible with '%#N' (declared %P)", entity, previous_entity, ppos);
                        } else {
                                unsigned old_storage_class = prev_decl->storage_class;
 
@@ -4278,9 +4231,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                                                !prev_decl->used                  &&
                                                !(prev_decl->modifiers & DM_USED) &&
                                                prev_decl->storage_class == STORAGE_CLASS_STATIC) {
-                                       warningf(&previous_entity->base.source_position,
-                                                       "unnecessary static forward declaration for '%#T'",
-                                                       prev_decl->type, symbol);
+                                       warningf(ppos, "unnecessary static forward declaration for '%#N'", previous_entity);
                                }
 
                                storage_class_t new_storage_class = decl->storage_class;
@@ -4304,8 +4255,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                                                                if (warning.missing_prototypes &&
                                                                                prev_type->function.unspecified_parameters &&
                                                                                !is_sym_main(symbol)) {
-                                                                       warningf(pos, "no previous prototype for '%#T'",
-                                                                                       orig_type, symbol);
+                                                                       warningf(pos, "no previous prototype for '%#N'", entity);
                                                                }
                                                        } else if (new_storage_class == STORAGE_CLASS_NONE) {
                                                                new_storage_class = STORAGE_CLASS_EXTERN;
@@ -4331,18 +4281,13 @@ warn_redundant_declaration: ;
                                        } else if (!is_definition        &&
                                                        warning.redundant_decls  &&
                                                        is_type_valid(prev_type) &&
-                                                       strcmp(previous_entity->base.source_position.input_name,
-                                                               "<builtin>") != 0) {
-                                               warningf(pos,
-                                                        "redundant declaration for '%Y' (declared %P)",
-                                                        symbol, &previous_entity->base.source_position);
+                                                       strcmp(ppos->input_name, "<builtin>") != 0) {
+                                               warningf(pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
                                        }
                                } else if (current_function == NULL) {
                                        if (old_storage_class != STORAGE_CLASS_STATIC &&
                                                        new_storage_class == STORAGE_CLASS_STATIC) {
-                                               errorf(pos,
-                                                      "static declaration of '%Y' follows non-static declaration (declared %P)",
-                                                      symbol, &previous_entity->base.source_position);
+                                               errorf(pos, "static declaration of '%Y' follows non-static declaration (declared %P)", symbol, ppos);
                                        } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
                                                prev_decl->storage_class          = STORAGE_CLASS_NONE;
                                                prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
@@ -4355,12 +4300,9 @@ warn_redundant_declaration: ;
                                } else if (is_type_valid(prev_type)) {
                                        if (old_storage_class == new_storage_class) {
 error_redeclaration:
-                                               errorf(pos, "redeclaration of '%Y' (declared %P)",
-                                                               symbol, &previous_entity->base.source_position);
+                                               errorf(pos, "redeclaration of '%Y' (declared %P)", symbol, ppos);
                                        } else {
-                                               errorf(pos,
-                                                               "redeclaration of '%Y' with different linkage (declared %P)",
-                                                               symbol, &previous_entity->base.source_position);
+                                               errorf(pos, "redeclaration of '%Y' with different linkage (declared %P)", symbol, ppos);
                                        }
                                }
                        }
@@ -4372,11 +4314,10 @@ error_redeclaration:
                        return previous_entity;
                }
 
-               if (warning.shadow) {
-                       warningf(pos, "%s '%Y' shadows %s (declared %P)",
-                                       get_entity_kind_name(entity->kind), symbol,
-                                       get_entity_kind_name(previous_entity->kind),
-                                       &previous_entity->base.source_position);
+               if (warning.shadow ||
+                               (warning.shadow_local && previous_entity->base.parent_scope != file_scope)) {
+                       char const *const what = get_entity_kind_name(previous_entity->kind);
+                       warningf(pos, "'%N' shadows %s (declared %P)", entity, what, ppos);
                }
        }
 
@@ -4384,20 +4325,16 @@ error_redeclaration:
                if (is_definition &&
                                entity->declaration.storage_class != STORAGE_CLASS_STATIC) {
                        if (warning.missing_prototypes && !is_sym_main(symbol)) {
-                               warningf(pos, "no previous prototype for '%#T'",
-                                        entity->declaration.type, symbol);
+                               warningf(pos, "no previous prototype for '%#N'", entity);
                        } else if (warning.missing_declarations && !is_sym_main(symbol)) {
-                               warningf(pos, "no previous declaration for '%#T'",
-                                        entity->declaration.type, symbol);
+                               warningf(pos, "no previous declaration for '%#N'", entity);
                        }
                }
-       } else if (warning.missing_declarations &&
-                       entity->kind == ENTITY_VARIABLE &&
-                       current_scope == file_scope) {
-               declaration_t *declaration = &entity->declaration;
-               if (declaration->storage_class == STORAGE_CLASS_NONE) {
-                       warningf(pos, "no previous declaration for '%#T'",
-                                declaration->type, symbol);
+       } else if (entity->kind == ENTITY_VARIABLE) {
+               if (warning.missing_declarations &&
+             current_scope == file_scope  &&
+             entity->declaration.storage_class == STORAGE_CLASS_NONE) {
+                       warningf(pos, "no previous declaration for '%#N'", entity);
                }
        }
 
@@ -4406,7 +4343,6 @@ finish:
        assert(current_scope != NULL);
 
        entity->base.parent_scope = current_scope;
-       entity->base.namespc      = NAMESPACE_NORMAL;
        environment_push(entity);
        append_entity(current_scope, entity);
 
@@ -4420,20 +4356,14 @@ static void parser_error_multiple_definition(entity_t *entity,
               entity->base.symbol, &entity->base.source_position);
 }
 
-static bool is_declaration_specifier(const token_t *token,
-                                     bool only_specifiers_qualifiers)
+static bool is_declaration_specifier(const token_t *token)
 {
        switch (token->type) {
-               TYPE_SPECIFIERS
-               TYPE_QUALIFIERS
+               DECLARATION_START
                        return true;
                case T_IDENTIFIER:
                        return is_typedef_symbol(token->symbol);
 
-               case T___extension__:
-               STORAGE_CLASSES
-                       return !only_specifiers_qualifiers;
-
                default:
                        return false;
        }
@@ -4444,14 +4374,12 @@ static void parse_init_declarator_rest(entity_t *entity)
        type_t *orig_type = type_error_type;
 
        if (entity->base.kind == ENTITY_TYPEDEF) {
-               errorf(&entity->base.source_position,
-                      "typedef '%Y' is initialized (use __typeof__ instead)",
-                      entity->base.symbol);
+               source_position_t const *const pos = &entity->base.source_position;
+               errorf(pos, "'%N' is initialized (use __typeof__ instead)", entity);
        } else {
                assert(is_declaration(entity));
                orig_type = entity->declaration.type;
        }
-       eat('=');
 
        type_t *type = skip_typeref(orig_type);
 
@@ -4459,6 +4387,7 @@ static void parse_init_declarator_rest(entity_t *entity)
                        && entity->variable.initializer != NULL) {
                parser_error_multiple_definition(entity, HERE);
        }
+       eat('=');
 
        declaration_t *const declaration = &entity->declaration;
        bool must_be_constant = false;
@@ -4468,9 +4397,8 @@ static void parse_init_declarator_rest(entity_t *entity)
        }
 
        if (is_type_function(type)) {
-               errorf(&entity->base.source_position,
-                      "function '%#T' is initialized like a variable",
-                      orig_type, entity->base.symbol);
+               source_position_t const *const pos = &entity->base.source_position;
+               errorf(pos, "'%N' is initialized like a variable", entity);
                orig_type = type_error_type;
        }
 
@@ -4538,8 +4466,7 @@ static void check_variable_type_complete(entity_t *ent)
                        decl->storage_class == STORAGE_CLASS_STATIC)
                return;
 
-       type_t *const orig_type = decl->type;
-       type_t *const type      = skip_typeref(orig_type);
+       type_t *const type = skip_typeref(decl->type);
        if (!is_type_incomplete(type))
                return;
 
@@ -4550,8 +4477,7 @@ static void check_variable_type_complete(entity_t *ent)
                return;
        }
 
-       errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
-                       orig_type, ent->base.symbol);
+       errorf(&ent->base.source_position, "variable '%#N' has incomplete type", ent);
 }
 
 
@@ -4574,9 +4500,8 @@ static void parse_declaration_rest(entity_t *ndeclaration,
                        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);
+                                       source_position_t const *const pos = &entity->base.source_position;
+                                       errorf(pos, "reference '%#N' must be initialized", entity);
                                }
                        }
                }
@@ -4601,22 +4526,20 @@ end_error:
 static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
 {
        symbol_t *symbol = entity->base.symbol;
-       if (symbol == NULL) {
-               errorf(HERE, "anonymous declaration not valid as function parameter");
+       if (symbol == NULL)
                return entity;
-       }
 
        assert(entity->base.namespc == NAMESPACE_NORMAL);
        entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL);
        if (previous_entity == NULL
                        || previous_entity->base.parent_scope != current_scope) {
-               errorf(HERE, "expected declaration of a function parameter, found '%Y'",
+               errorf(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'",
                       symbol);
                return entity;
        }
 
        if (is_definition) {
-               errorf(HERE, "parameter '%Y' is initialised", entity->base.symbol);
+               errorf(HERE, "'%N' is initialised", entity);
        }
 
        return record_entity(entity, false);
@@ -4625,10 +4548,8 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
 static void parse_declaration(parsed_declaration_func finished_declaration,
                               declarator_flags_t      flags)
 {
-       declaration_specifiers_t specifiers;
-       memset(&specifiers, 0, sizeof(specifiers));
-
        add_anchor_token(';');
+       declaration_specifiers_t specifiers;
        parse_declaration_specifiers(&specifiers);
        rem_anchor_token(';');
 
@@ -4735,14 +4656,13 @@ decl_list_end:
 
                type_t *parameter_type = parameter->declaration.type;
                if (parameter_type == NULL) {
+                       source_position_t const* const pos = &parameter->base.source_position;
                        if (strict_mode) {
-                               errorf(HERE, "no type specified for function parameter '%Y'",
-                                      parameter->base.symbol);
+                               errorf(pos, "no type specified for function '%N'", parameter);
                                parameter_type = type_error_type;
                        } else {
                                if (warning.implicit_int) {
-                                       warningf(HERE, "no type specified for function parameter '%Y', using 'int'",
-                                                parameter->base.symbol);
+                                       warningf(pos, "no type specified for function '%N', using 'int'", parameter);
                                }
                                parameter_type = type_int;
                        }
@@ -4768,25 +4688,22 @@ decl_list_end:
                                parameter_type = not_promoted;
                        }
                }
-               function_parameter_t *const parameter
+               function_parameter_t *const function_parameter
                        = allocate_parameter(parameter_type);
 
-               *anchor = parameter;
-               anchor  = &parameter->next;
+               *anchor = function_parameter;
+               anchor  = &function_parameter->next;
        }
 
        new_type->function.parameters = parameters;
        new_type = identify_new_type(new_type);
 
        if (warning.other && need_incompatible_warning) {
-               type_t *proto_type_type = proto_type->declaration.type;
-               warningf(HERE,
-                        "declaration '%#T' is incompatible with '%#T' (declared %P)",
-                        proto_type_type, proto_type->base.symbol,
-                        new_type, entity->base.symbol,
-                        &proto_type->base.source_position);
+               source_position_t const *const pos  = &entity->base.source_position;
+               source_position_t const *const ppos = &proto_type->base.source_position;
+               symbol_t          const *const sym  = entity->base.symbol;
+               warningf(pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos);
        }
-
        entity->declaration.type = new_type;
 
        rem_anchor_token('{');
@@ -4802,9 +4719,8 @@ static void print_in_function(void)
 {
        if (first_err) {
                first_err = false;
-               diagnosticf("%s: In function '%Y':\n",
-                           current_function->base.base.source_position.input_name,
-                           current_function->base.base.symbol);
+               char const *const file = current_function->base.base.source_position.input_name;
+               diagnosticf("%s: In '%N':\n", file, (entity_t const*)current_function);
        }
 }
 
@@ -4822,12 +4738,10 @@ static void check_labels(void)
                        continue;
 
                label_t *label = goto_statement->label;
-
-               label->used = true;
                if (label->base.source_position.input_name == NULL) {
                        print_in_function();
-                       errorf(&goto_statement->base.source_position,
-                              "label '%Y' used but not defined", label->base.symbol);
+                       source_position_t const *const pos = &goto_statement->base.source_position;
+                       errorf(pos, "'%N' used but not defined", (entity_t const*)label);
                 }
        }
 
@@ -4839,8 +4753,8 @@ static void check_labels(void)
 
                        if (! label->used) {
                                print_in_function();
-                               warningf(&label_statement->base.source_position,
-                                        "label '%Y' defined but not used", label->base.symbol);
+                               source_position_t const *const pos = &label_statement->base.source_position;
+                               warningf(pos, "'%N' defined but not used", (entity_t const*)label);
                        }
                }
        }
@@ -4859,14 +4773,10 @@ static void warn_unused_entity(entity_t *entity, entity_t *last)
 
                if (!declaration->used) {
                        print_in_function();
-                       const char *what = get_entity_kind_name(entity->kind);
-                       warningf(&entity->base.source_position, "%s '%Y' is unused",
-                                what, entity->base.symbol);
+                       warningf(&entity->base.source_position, "'%N' is unused", entity);
                } else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) {
                        print_in_function();
-                       const char *what = get_entity_kind_name(entity->kind);
-                       warningf(&entity->base.source_position, "%s '%Y' is never read",
-                                what, entity->base.symbol);
+                       warningf(&entity->base.source_position, "'%N' is never read", entity);
                }
        }
 }
@@ -5065,15 +4975,15 @@ static void check_reachable(statement_t *const stmt)
                case STATEMENT_DECLARATION: {
                        declaration_statement_t const *const decl = &stmt->declaration;
                        entity_t                const *      ent  = decl->declarations_begin;
-                       entity_t                const *const last = decl->declarations_end;
+                       entity_t                const *const last_decl = decl->declarations_end;
                        if (ent != NULL) {
                                for (;; ent = ent->base.next) {
                                        if (ent->kind                 == ENTITY_VARIABLE &&
-                                                       ent->variable.initializer != NULL            &&
-                                                       !initializer_returns(ent->variable.initializer)) {
+                                           ent->variable.initializer != NULL            &&
+                                           !initializer_returns(ent->variable.initializer)) {
                                                return;
                                        }
-                                       if (ent == last)
+                                       if (ent == last_decl)
                                                break;
                                }
                        }
@@ -5522,10 +5432,8 @@ static void parse_external_declaration(void)
 {
        /* function-definitions and declarations both start with declaration
         * specifiers */
-       declaration_specifiers_t specifiers;
-       memset(&specifiers, 0, sizeof(specifiers));
-
        add_anchor_token(';');
+       declaration_specifiers_t specifiers;
        parse_declaration_specifiers(&specifiers);
        rem_anchor_token(';');
 
@@ -5573,30 +5481,27 @@ static void parse_external_declaration(void)
 
        if (!is_type_function(type)) {
                if (is_type_valid(type)) {
-                       errorf(HERE, "declarator '%#T' has a body but is not a function type",
-                              type, ndeclaration->base.symbol);
+                       errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
                }
                eat_block();
                return;
-       } else if (is_typeref(orig_type)) {
+       }
+
+       source_position_t const *const pos = &ndeclaration->base.source_position;
+       if (is_typeref(orig_type)) {
                /* Â§6.9.1:2 */
-               errorf(&ndeclaration->base.source_position,
-                               "type of function definition '%#T' is a typedef",
-                               orig_type, ndeclaration->base.symbol);
+               errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
        }
 
        if (warning.aggregate_return &&
            is_type_compound(skip_typeref(type->function.return_type))) {
-               warningf(HERE, "function '%Y' returns an aggregate",
-                        ndeclaration->base.symbol);
+               warningf(pos, "'%N' returns an aggregate", ndeclaration);
        }
        if (warning.traditional && !type->function.unspecified_parameters) {
-               warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'",
-                       ndeclaration->base.symbol);
+               warningf(pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
        }
        if (warning.old_style_definition && type->function.unspecified_parameters) {
-               warningf(HERE, "old-style function definition '%Y'",
-                       ndeclaration->base.symbol);
+               warningf(pos, "old-style definition of '%N'", ndeclaration);
        }
 
        /* Â§6.7.5.3:14 a function definition with () means no
@@ -5673,9 +5578,8 @@ static void parse_external_declaration(void)
                        if (warning.missing_noreturn &&
                            noreturn_candidate       &&
                            !(function->base.modifiers & DM_NORETURN)) {
-                               warningf(&body->base.source_position,
-                                        "function '%#T' is candidate for attribute 'noreturn'",
-                                        type, entity->base.symbol);
+                               source_position_t const *const pos = &body->base.source_position;
+                               warningf(pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
                        }
                }
 
@@ -5704,8 +5608,7 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
        il_size_t bit_size;
        type_t *skipped_type = skip_typeref(base_type);
        if (!is_type_integer(skipped_type)) {
-               errorf(HERE, "bitfield base type '%T' is not an integer type",
-                      base_type);
+               errorf(source_position, "bitfield base type '%T' is not an integer type", base_type);
                bit_size = 0;
        } else {
                bit_size = get_type_size(base_type) * 8;
@@ -5766,16 +5669,12 @@ static void check_deprecated(const source_position_t *source_position,
        if ((entity->declaration.modifiers & DM_DEPRECATED) == 0)
                return;
 
-       char const *const prefix = get_entity_kind_name(entity->kind);
-       const char *deprecated_string
-                       = get_deprecated_string(entity->declaration.attributes);
-       if (deprecated_string != NULL) {
-               warningf(source_position, "%s '%Y' is deprecated (declared %P): \"%s\"",
-                                prefix, entity->base.symbol, &entity->base.source_position,
-                                deprecated_string);
+       source_position_t const *const pos = &entity->base.source_position;
+       char              const* const msg = get_deprecated_string(entity->declaration.attributes);
+       if (msg != NULL) {
+               warningf(source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, pos, msg);
        } else {
-               warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix,
-                                entity->base.symbol, &entity->base.source_position);
+               warningf(source_position, "'%N' is deprecated (declared %P)", entity, pos);
        }
 }
 
@@ -5870,8 +5769,7 @@ static void parse_compound_declarators(compound_t *compound,
                                anchor = &(*anchor)->next;
                        *anchor = specifiers->attributes;
 
-                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
-                       entity->base.namespc                       = NAMESPACE_NORMAL;
+                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL);
                        entity->base.source_position               = source_position;
                        entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
                        entity->declaration.storage_class          = STORAGE_CLASS_NONE;
@@ -5885,9 +5783,9 @@ static void parse_compound_declarators(compound_t *compound,
                } else {
                        entity = parse_declarator(specifiers,
                                        DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
+                       source_position_t const *const pos = &entity->base.source_position;
                        if (entity->kind == ENTITY_TYPEDEF) {
-                               errorf(&entity->base.source_position,
-                                               "typedef not allowed as compound member");
+                               errorf(pos, "typedef not allowed as compound member");
                        } else {
                                assert(entity->kind == ENTITY_COMPOUND_MEMBER);
 
@@ -5896,9 +5794,8 @@ static void parse_compound_declarators(compound_t *compound,
                                if (symbol != NULL) {
                                        entity_t *prev = find_compound_entry(compound, symbol);
                                        if (prev != NULL) {
-                                               errorf(&entity->base.source_position,
-                                                               "multiple declarations of symbol '%Y' (declared %P)",
-                                                               symbol, &prev->base.source_position);
+                                               source_position_t const *const ppos = &prev->base.source_position;
+                                               errorf(pos, "multiple declarations of symbol '%Y' (declared %P)", symbol, ppos);
                                        }
                                }
 
@@ -5918,17 +5815,13 @@ static void parse_compound_declarators(compound_t *compound,
                                        type_t *orig_type = entity->declaration.type;
                                        type_t *type      = skip_typeref(orig_type);
                                        if (is_type_function(type)) {
-                                               errorf(&entity->base.source_position,
-                                                      "compound member '%Y' must not have function type '%T'",
-                                                               entity->base.symbol, orig_type);
+                                               errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
                                        } else if (is_type_incomplete(type)) {
                                                /* Â§6.7.2.1:16 flexible array member */
                                                if (!is_type_array(type)       ||
                                                                token.type          != ';' ||
                                                                look_ahead(1)->type != '}') {
-                                                       errorf(&entity->base.source_position,
-                                                              "compound member '%Y' has incomplete type '%T'",
-                                                                       entity->base.symbol, orig_type);
+                                                       errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
                                                }
                                        }
                                }
@@ -5954,9 +5847,7 @@ static void parse_compound_type_entries(compound_t *compound)
                        break;
                }
                declaration_specifiers_t specifiers;
-               memset(&specifiers, 0, sizeof(specifiers));
                parse_declaration_specifiers(&specifiers);
-
                parse_compound_declarators(compound, &specifiers);
        }
        rem_anchor_token('}');
@@ -5969,14 +5860,13 @@ static void parse_compound_type_entries(compound_t *compound)
 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
                        || specifiers.thread_local) {
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
-               errorf(HERE, "typename must not have a storage class");
+               errorf(&specifiers.source_position, "typename must not have a storage class");
        }
 
        type_t *result = parse_abstract_declarator(specifiers.type);
@@ -5997,7 +5887,7 @@ struct expression_parser_function_t {
        parse_expression_infix_function  infix_parser;
 };
 
-expression_parser_function_t expression_parsers[T_LAST_TOKEN];
+static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
 /**
  * Prints an error message if an expression was expected but not read
@@ -6245,21 +6135,15 @@ static entity_t *create_implicit_function(symbol_t *symbol,
        ntype->function.linkage                = LINKAGE_C;
        type_t *type                           = identify_new_type(ntype);
 
-       entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
+       entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol);
        entity->declaration.storage_class          = STORAGE_CLASS_EXTERN;
        entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
        entity->declaration.type                   = type;
        entity->declaration.implicit               = true;
-       entity->base.namespc                       = NAMESPACE_NORMAL;
-       entity->base.symbol                        = symbol;
        entity->base.source_position               = *source_position;
 
-       if (current_scope != NULL) {
-               bool strict_prototypes_old = warning.strict_prototypes;
-               warning.strict_prototypes  = false;
+       if (current_scope != NULL)
                record_entity(entity, false);
-               warning.strict_prototypes = strict_prototypes_old;
-       }
 
        return entity;
 }
@@ -6363,7 +6247,8 @@ static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol,
           construct a hashmap here... */
        entity_t *entity = scope->entities;
        for ( ; entity != NULL; entity = entity->base.next) {
-               if (entity->base.symbol == symbol && entity->base.namespc == namespc)
+               if (entity->base.symbol == symbol
+                   && (namespace_tag_t)entity->base.namespc == namespc)
                        break;
        }
 
@@ -6408,7 +6293,11 @@ static entity_t *parse_qualified_identifier(void)
                default:
                        errorf(&pos, "'%Y' must be a namespace, class, struct or union (but is a %s)",
                               symbol, get_entity_kind_name(entity->kind));
-                       goto end_error;
+
+                       /* skip further qualifications */
+                       while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+
+                       return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
                }
        }
 
@@ -6429,17 +6318,12 @@ static entity_t *parse_qualified_identifier(void)
        }
 
        return entity;
-
-end_error:
-       /* skip further qualifications */
-       while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
-
-       return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
 }
 
 static expression_t *parse_reference(void)
 {
-       entity_t *entity = parse_qualified_identifier();
+       source_position_t const pos    = token.source_position;
+       entity_t         *const entity = parse_qualified_identifier();
 
        type_t *orig_type;
        if (is_declaration(entity)) {
@@ -6458,9 +6342,10 @@ static expression_t *parse_reference(void)
        if (entity->kind == ENTITY_ENUM_VALUE)
                kind = EXPR_REFERENCE_ENUM_VALUE;
 
-       expression_t *expression     = allocate_expression_zero(kind);
-       expression->reference.entity = entity;
-       expression->base.type        = type;
+       expression_t *expression         = allocate_expression_zero(kind);
+       expression->base.source_position = pos;
+       expression->base.type            = type;
+       expression->reference.entity     = entity;
 
        /* this declaration is used */
        if (is_declaration(entity)) {
@@ -6480,13 +6365,12 @@ static expression_t *parse_reference(void)
                current_function->need_closure = true;
        }
 
-       check_deprecated(HERE, entity);
+       check_deprecated(&pos, entity);
 
        if (warning.init_self && entity == current_init_decl && !in_type_prop
            && entity->kind == ENTITY_VARIABLE) {
                current_init_decl = NULL;
-               warningf(HERE, "variable '%#T' is initialized by itself",
-                        entity->declaration.type, entity->base.symbol);
+               warningf(&pos, "variable '%#N' is initialized by itself", entity);
        }
 
        return expression;
@@ -6563,10 +6447,11 @@ static expression_t *parse_compound_literal(type_t *type)
  */
 static expression_t *parse_cast(void)
 {
-       add_anchor_token(')');
-
        source_position_t source_position = token.source_position;
 
+       eat('(');
+       add_anchor_token(')');
+
        type_t *type = parse_typename();
 
        rem_anchor_token(')');
@@ -6597,10 +6482,11 @@ end_error:
  */
 static expression_t *parse_statement_expression(void)
 {
-       add_anchor_token(')');
-
        expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
 
+       eat('(');
+       add_anchor_token(')');
+
        statement_t *statement          = parse_compound_statement(true);
        statement->compound.stmt_expr   = true;
        expression->statement.statement = statement;
@@ -6632,22 +6518,20 @@ end_error:
  */
 static expression_t *parse_parenthesized_expression(void)
 {
-       eat('(');
-
-       switch (token.type) {
+       token_t const* const la1 = look_ahead(1);
+       switch (la1->type) {
        case '{':
                /* gcc extension: a statement expression */
                return parse_statement_expression();
 
-       TYPE_QUALIFIERS
-       TYPE_SPECIFIERS
-               return parse_cast();
        case T_IDENTIFIER:
-               if (is_typedef_symbol(token.symbol)) {
+               if (is_typedef_symbol(la1->symbol)) {
+       DECLARATION_START
                        return parse_cast();
                }
        }
 
+       eat('(');
        add_anchor_token(')');
        expression_t *result = parse_expression();
        result->base.parenthesized = true;
@@ -7028,40 +6912,27 @@ end_error:
 }
 
 /**
- * Return the declaration for a given label symbol or create a new one.
- *
- * @param symbol  the symbol of the label
+ * Return the label for the current symbol or create a new one.
  */
-static label_t *get_label(symbol_t *symbol)
+static label_t *get_label(void)
 {
-       entity_t *label;
+       assert(token.type == T_IDENTIFIER);
        assert(current_function != NULL);
 
-       label = get_entity(symbol, NAMESPACE_LABEL);
-       /* if we found a local label, we already created the declaration */
+       entity_t *label = get_entity(token.symbol, NAMESPACE_LABEL);
+       /* If we find a local label, we already created the declaration. */
        if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
                if (label->base.parent_scope != current_scope) {
                        assert(label->base.parent_scope->depth < current_scope->depth);
                        current_function->goto_to_outer = true;
                }
-               return &label->label;
-       }
-
-       label = get_entity(symbol, NAMESPACE_LABEL);
-       /* if we found a label in the same function, then we already created the
-        * declaration */
-       if (label != NULL
-                       && label->base.parent_scope == &current_function->parameters) {
-               return &label->label;
+       } else if (label == NULL || label->base.parent_scope != &current_function->parameters) {
+               /* There is no matching label in the same function, so create a new one. */
+               label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.symbol);
+               label_push(label);
        }
 
-       /* otherwise we need to create a new one */
-       label               = allocate_entity_zero(ENTITY_LABEL);
-       label->base.namespc = NAMESPACE_LABEL;
-       label->base.symbol  = symbol;
-
-       label_push(label);
-
+       eat(T_IDENTIFIER);
        return &label->label;
 }
 
@@ -7074,24 +6945,20 @@ static expression_t *parse_label_address(void)
        eat(T_ANDAND);
        if (token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
-               goto end_error;
+               return create_invalid_expression();
        }
-       symbol_t *symbol = token.symbol;
-       next_token();
 
-       label_t *label       = get_label(symbol);
+       label_t *const label = get_label();
        label->used          = true;
        label->address_taken = true;
 
        expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS);
        expression->base.source_position = source_position;
 
-       /* label address is threaten as a void pointer */
+       /* label address is treated as a void pointer */
        expression->base.type           = type_void_ptr;
        expression->label_address.label = label;
        return expression;
-end_error:
-       return create_invalid_expression();
 }
 
 /**
@@ -7177,9 +7044,11 @@ static expression_t *parse_primary_expression(void)
                        return parse_reference();
                }
                /* FALLTHROUGH */
-       TYPENAME_START {
-               source_position_t  const pos  = *HERE;
-               type_t const      *const type = parse_typename();
+       DECLARATION_START {
+               source_position_t const  pos = *HERE;
+               declaration_specifiers_t specifiers;
+               parse_declaration_specifiers(&specifiers);
+               type_t const *const type = parse_abstract_declarator(specifiers.type);
                errorf(&pos, "encountered type '%T' while parsing expression", type);
                return create_invalid_expression();
        }
@@ -7190,29 +7059,15 @@ static expression_t *parse_primary_expression(void)
        return create_invalid_expression();
 }
 
-/**
- * Check if the expression has the character type and issue a warning then.
- */
-static void check_for_char_index_type(const expression_t *expression)
-{
-       type_t       *const type      = expression->base.type;
-       const type_t *const base_type = skip_typeref(type);
-
-       if (is_type_atomic(base_type, ATOMIC_TYPE_CHAR) &&
-                       warning.char_subscripts) {
-               warningf(&expression->base.source_position,
-                        "array subscript has type '%T'", type);
-       }
-}
-
 static expression_t *parse_array_expression(expression_t *left)
 {
-       expression_t *expression = allocate_expression_zero(EXPR_ARRAY_ACCESS);
+       expression_t              *const expr = allocate_expression_zero(EXPR_ARRAY_ACCESS);
+       array_access_expression_t *const arr  = &expr->array_access;
 
        eat('[');
        add_anchor_token(']');
 
-       expression_t *inside = parse_expression();
+       expression_t *const inside = parse_expression();
 
        type_t *const orig_type_left   = left->base.type;
        type_t *const orig_type_inside = inside->base.type;
@@ -7220,36 +7075,46 @@ static expression_t *parse_array_expression(expression_t *left)
        type_t *const type_left   = skip_typeref(orig_type_left);
        type_t *const type_inside = skip_typeref(orig_type_inside);
 
-       type_t                    *return_type;
-       array_access_expression_t *array_access = &expression->array_access;
+       expression_t *ref;
+       expression_t *idx;
+       type_t       *idx_type;
+       type_t       *res_type;
        if (is_type_pointer(type_left)) {
-               return_type             = type_left->pointer.points_to;
-               array_access->array_ref = left;
-               array_access->index     = inside;
-               check_for_char_index_type(inside);
+               ref      = left;
+               idx      = inside;
+               idx_type = type_inside;
+               res_type = type_left->pointer.points_to;
+               goto check_idx;
        } else if (is_type_pointer(type_inside)) {
-               return_type             = type_inside->pointer.points_to;
-               array_access->array_ref = inside;
-               array_access->index     = left;
-               array_access->flipped   = true;
-               check_for_char_index_type(left);
+               arr->flipped = true;
+               ref      = inside;
+               idx      = left;
+               idx_type = type_left;
+               res_type = type_inside->pointer.points_to;
+check_idx:
+               res_type = automatic_type_conversion(res_type);
+               if (!is_type_integer(idx_type)) {
+                       errorf(&idx->base.source_position, "array subscript must have integer type");
+               } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR) && warning.char_subscripts) {
+                       warningf(&idx->base.source_position, "array subscript has char type");
+               }
        } else {
                if (is_type_valid(type_left) && is_type_valid(type_inside)) {
-                       errorf(HERE,
-                               "array access on object with non-pointer types '%T', '%T'",
-                               orig_type_left, orig_type_inside);
+                       errorf(&expr->base.source_position, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside);
                }
-               return_type             = type_error_type;
-               array_access->array_ref = left;
-               array_access->index     = inside;
+               res_type = type_error_type;
+               ref      = left;
+               idx      = inside;
        }
 
-       expression->base.type = automatic_type_conversion(return_type);
+       arr->array_ref = ref;
+       arr->index     = idx;
+       arr->base.type = res_type;
 
        rem_anchor_token(']');
        expect(']', end_error);
 end_error:
-       return expression;
+       return expr;
 }
 
 static expression_t *parse_typeprop(expression_kind_t const kind)
@@ -7265,7 +7130,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
 
        type_t       *orig_type;
        expression_t *expression;
-       if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
+       if (token.type == '(' && is_declaration_specifier(look_ahead(1))) {
                next_token();
                add_anchor_token(')');
                orig_type = parse_typename();
@@ -7574,36 +7439,36 @@ static expression_t *parse_call_expression(expression_t *expression)
                }
 
                if (parameter != NULL) {
-                       errorf(HERE, "too few arguments to function '%E'", expression);
+                       errorf(&expression->base.source_position, "too few arguments to function '%E'", expression);
                } else if (argument != NULL && !function_type->variadic) {
-                       errorf(HERE, "too many arguments to function '%E'", expression);
+                       errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression);
                }
        }
 
        /* do default promotion for other arguments */
        for (; argument != NULL; argument = argument->next) {
-               type_t *type = argument->expression->base.type;
-               if (!is_type_object(skip_typeref(type))) {
+               type_t *argument_type = argument->expression->base.type;
+               if (!is_type_object(skip_typeref(argument_type))) {
                        errorf(&argument->expression->base.source_position,
                               "call argument '%E' must not be void", argument->expression);
                }
 
-               type = get_default_promoted_type(type);
+               argument_type = get_default_promoted_type(argument_type);
 
                argument->expression
-                       = create_implicit_cast(argument->expression, type);
+                       = create_implicit_cast(argument->expression, argument_type);
        }
 
-       check_format(&result->call);
+       check_format(call);
 
        if (warning.aggregate_return &&
            is_type_compound(skip_typeref(function_type->return_type))) {
-               warningf(&result->base.source_position,
+               warningf(&expression->base.source_position,
                         "function call has aggregate value");
        }
 
-       if (call->function->kind == EXPR_REFERENCE) {
-               reference_expression_t *reference = &call->function->reference;
+       if (expression->kind == EXPR_REFERENCE) {
+               reference_expression_t *reference = &expression->reference;
                if (reference->entity->kind == ENTITY_FUNCTION &&
                    reference->entity->function.btk != bk_none)
                        handle_builtin_argument_restrictions(call);
@@ -7659,9 +7524,9 @@ static void warn_reference_address_as_bool(expression_t const* expr)
 
        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);
+               source_position_t const *const pos = &expr->base.source_position;
+               entity_t          const *const ent = expr->reference.entity;
+               warningf(pos, "the address of '%N' will always evaluate as 'true'", ent);
        }
 }
 
@@ -7798,13 +7663,10 @@ end_error:;
                        }
                        result_type = pointer_type;
                } else {
-                       if (is_type_valid(other_type)) {
-                               type_error_incompatible("while parsing conditional",
-                                               &expression->base.source_position, true_type, false_type);
-                       }
-                       result_type = type_error_type;
+                       goto types_incompatible;
                }
        } else {
+types_incompatible:
                if (is_type_valid(true_type) && is_type_valid(false_type)) {
                        type_error_incompatible("while parsing conditional",
                                                &conditional->base.source_position, true_type,
@@ -8091,9 +7953,8 @@ static void set_address_taken(expression_t *expression, bool may_be_register)
 
        if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
                        && !may_be_register) {
-               errorf(&expression->base.source_position,
-                      "address of register %s '%Y' requested",
-                      get_entity_kind_name(entity->kind), entity->base.symbol);
+               source_position_t const *const pos = &expression->base.source_position;
+               errorf(pos, "address of register '%N' requested", entity);
        }
 
        if (entity->kind == ENTITY_VARIABLE) {
@@ -8485,25 +8346,6 @@ static void warn_string_literal_address(expression_t const* expr)
        }
 }
 
-static void warn_comparison_in_comparison(const expression_t *const expr)
-{
-       if (expr->base.parenthesized)
-               return;
-       switch (expr->base.kind) {
-               case EXPR_BINARY_LESS:
-               case EXPR_BINARY_GREATER:
-               case EXPR_BINARY_LESSEQUAL:
-               case EXPR_BINARY_GREATEREQUAL:
-               case EXPR_BINARY_NOTEQUAL:
-               case EXPR_BINARY_EQUAL:
-                       warningf(&expr->base.source_position,
-                                       "comparisons like 'x <= y < z' do not have their mathematical meaning");
-                       break;
-               default:
-                       break;
-       }
-}
-
 static bool maybe_negative(expression_t const *const expr)
 {
        switch (is_constant_expression(expr)) {
@@ -8513,39 +8355,47 @@ static bool maybe_negative(expression_t const *const expr)
        }
 }
 
-/**
- * Check the semantics of comparison expressions.
- *
- * @param expression   The expression to check.
- */
-static void semantic_comparison(binary_expression_t *expression)
+static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other)
 {
-       expression_t *left  = expression->left;
-       expression_t *right = expression->right;
-
        if (warning.address) {
-               warn_string_literal_address(left);
-               warn_string_literal_address(right);
+               warn_string_literal_address(expr);
 
-               expression_t const* const func_left = get_reference_address(left);
-               if (func_left != NULL && is_null_pointer_constant(right)) {
-                       warningf(&expression->base.source_position,
-                                "the address of '%Y' will never be NULL",
-                                func_left->reference.entity->base.symbol);
+               expression_t const* const ref = get_reference_address(expr);
+               if (ref != NULL && is_null_pointer_constant(other)) {
+                       entity_t const *const ent = ref->reference.entity;
+                       warningf(pos, "the address of '%N' will never be NULL", ent);
                }
+       }
 
-               expression_t const* const func_right = get_reference_address(right);
-               if (func_right != NULL && is_null_pointer_constant(right)) {
-                       warningf(&expression->base.source_position,
-                                "the address of '%Y' will never be NULL",
-                                func_right->reference.entity->base.symbol);
+       if (warning.parentheses && !expr->base.parenthesized) {
+               switch (expr->base.kind) {
+                       case EXPR_BINARY_LESS:
+                       case EXPR_BINARY_GREATER:
+                       case EXPR_BINARY_LESSEQUAL:
+                       case EXPR_BINARY_GREATEREQUAL:
+                       case EXPR_BINARY_NOTEQUAL:
+                       case EXPR_BINARY_EQUAL:
+                               warningf(pos, "comparisons like 'x <= y < z' do not have their mathematical meaning");
+                               break;
+                       default:
+                               break;
                }
        }
+}
 
-       if (warning.parentheses) {
-               warn_comparison_in_comparison(left);
-               warn_comparison_in_comparison(right);
-       }
+/**
+ * Check the semantics of comparison expressions.
+ *
+ * @param expression   The expression to check.
+ */
+static void semantic_comparison(binary_expression_t *expression)
+{
+       source_position_t const *const pos   = &expression->base.source_position;
+       expression_t            *const left  = expression->left;
+       expression_t            *const right = expression->right;
+
+       warn_comparison(pos, left, right);
+       warn_comparison(pos, right, left);
 
        type_t *orig_type_left  = left->base.type;
        type_t *orig_type_right = right->base.type;
@@ -8565,8 +8415,7 @@ static void semantic_comparison(binary_expression_t *expression)
                                /* TODO check whether constant value can be represented by other type */
                                if ((signed_left  && maybe_negative(left)) ||
                                                (signed_right && maybe_negative(right))) {
-                                       warningf(&expression->base.source_position,
-                                                       "comparison between signed and unsigned");
+                                       warningf(pos, "comparison between signed and unsigned");
                                }
                        }
                }
@@ -8578,8 +8427,7 @@ static void semantic_comparison(binary_expression_t *expression)
                    (expression->base.kind == EXPR_BINARY_EQUAL ||
                     expression->base.kind == EXPR_BINARY_NOTEQUAL) &&
                    is_type_float(arithmetic_type)) {
-                       warningf(&expression->base.source_position,
-                                "comparing floating point with == or != is unsafe");
+                       warningf(pos, "comparing floating point with == or != is unsafe");
                }
        } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
                /* TODO check compatibility */
@@ -8588,9 +8436,7 @@ static void semantic_comparison(binary_expression_t *expression)
        } else if (is_type_pointer(type_right)) {
                expression->left = create_implicit_cast(left, type_right);
        } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
-               type_error_incompatible("invalid operands in comparison",
-                                       &expression->base.source_position,
-                                       type_left, type_right);
+               type_error_incompatible("invalid operands in comparison", pos, type_left, type_right);
        }
        expression->base.type = c_mode & _CXX ? type_bool : type_int;
 }
@@ -8621,33 +8467,33 @@ static bool is_valid_assignment_lhs(expression_t const* const left)
        type_t *const type_left      = skip_typeref(orig_type_left);
 
        if (!is_lvalue(left)) {
-               errorf(HERE, "left hand side '%E' of assignment is not an lvalue",
+               errorf(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue",
                       left);
                return false;
        }
 
        if (left->kind == EXPR_REFERENCE
                        && left->reference.entity->kind == ENTITY_FUNCTION) {
-               errorf(HERE, "cannot assign to function '%E'", left);
+               errorf(&left->base.source_position, "cannot assign to function '%E'", left);
                return false;
        }
 
        if (is_type_array(type_left)) {
-               errorf(HERE, "cannot assign to array '%E'", left);
+               errorf(&left->base.source_position, "cannot assign to array '%E'", left);
                return false;
        }
        if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
-               errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
+               errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left,
                       orig_type_left);
                return false;
        }
        if (is_type_incomplete(type_left)) {
-               errorf(HERE, "left-hand side '%E' of assignment has incomplete type '%T'",
+               errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'",
                       left, orig_type_left);
                return false;
        }
        if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
-               errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
+               errorf(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields",
                       left, orig_type_left);
                return false;
        }
@@ -9480,8 +9326,7 @@ end_error:
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
                if (def_label != NULL) {
-                       errorf(HERE, "multiple default labels in one switch (previous declared %P)",
-                              &def_label->base.source_position);
+                       errorf(&statement->base.source_position, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position);
                } else {
                        current_switch->default_label = &statement->case_label;
 
@@ -9509,25 +9354,20 @@ end_error:
  */
 static statement_t *parse_label_statement(void)
 {
-       assert(token.type == T_IDENTIFIER);
-       symbol_t *symbol = token.symbol;
-       label_t  *label  = get_label(symbol);
-
        statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
-       statement->label.label       = label;
-
-       next_token();
+       label_t     *const label     = get_label();
+       statement->label.label = label;
 
        PUSH_PARENT(statement);
 
        /* if statement is already set then the label is defined twice,
         * otherwise it was just mentioned in a goto/local label declaration so far
         */
+       source_position_t const* const pos = &statement->base.source_position;
        if (label->statement != NULL) {
-               errorf(HERE, "duplicate label '%Y' (declared %P)",
-                      symbol, &label->base.source_position);
+               errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position);
        } else {
-               label->base.source_position = token.source_position;
+               label->base.source_position = *pos;
                label->statement            = statement;
        }
 
@@ -9621,10 +9461,8 @@ static void check_enum_cases(const switch_statement_t *statement)
                                break;
                        }
                }
-               if (! found) {
-                       warningf(&statement->base.source_position,
-                                "enumeration value '%Y' not handled in switch",
-                                entry->base.symbol);
+               if (!found) {
+                       warningf(&statement->base.source_position, "'%N' not handled in switch", entry);
                }
                last_value = value;
        }
@@ -9783,7 +9621,7 @@ static statement_t *parse_for(void)
        }
 
        if (next_if(';')) {
-       } else if (is_declaration_specifier(&token, false)) {
+       } else if (is_declaration_specifier(&token)) {
                parse_declaration(record_entity, DECL_FLAGS_NONE);
        } else {
                add_anchor_token(';');
@@ -9871,9 +9709,9 @@ static statement_t *parse_goto(void)
 
                statement->gotos.expression = expression;
        } else if (token.type == T_IDENTIFIER) {
-               symbol_t *symbol = token.symbol;
-               next_token();
-               statement->gotos.label = get_label(symbol);
+               label_t *const label = get_label();
+               label->used            = true;
+               statement->gotos.label = label;
        } else {
                if (GNU_MODE)
                        parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
@@ -10188,15 +10026,12 @@ static statement_t *parse_local_label_declaration(void)
                symbol_t *symbol = token.symbol;
                entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
                if (entity != NULL && entity->base.parent_scope == current_scope) {
-                       errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)",
-                              symbol, &entity->base.source_position);
+                       source_position_t const *const ppos = &entity->base.source_position;
+                       errorf(HERE, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                } else {
-                       entity = allocate_entity_zero(ENTITY_LOCAL_LABEL);
-
+                       entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol);
                        entity->base.parent_scope    = current_scope;
-                       entity->base.namespc         = NAMESPACE_LABEL;
                        entity->base.source_position = token.source_position;
-                       entity->base.symbol          = symbol;
 
                        *anchor = entity;
                        anchor  = &entity->base.next;
@@ -10237,10 +10072,8 @@ static void parse_namespace_definition(void)
        }
 
        if (entity == NULL) {
-               entity                       = allocate_entity_zero(ENTITY_NAMESPACE);
-               entity->base.symbol          = symbol;
+               entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
                entity->base.source_position = token.source_position;
-               entity->base.namespc         = NAMESPACE_NORMAL;
                entity->base.parent_scope    = current_scope;
        }
 
@@ -10657,7 +10490,6 @@ static void check_unused_globals(void)
                    declaration->storage_class != STORAGE_CLASS_STATIC)
                        continue;
 
-               type_t *const type = declaration->type;
                const char *s;
                if (entity->kind == ENTITY_FUNCTION) {
                        /* inhibit warning for static inline functions */
@@ -10669,8 +10501,7 @@ static void check_unused_globals(void)
                        s = "defined";
                }
 
-               warningf(&declaration->base.source_position, "'%#T' %s but not used",
-                       type, declaration->base.symbol, s);
+               warningf(&declaration->base.source_position, "'%#N' %s but not used", entity);
        }
 }
 
@@ -10695,7 +10526,8 @@ static void parse_linkage_specification(void)
 {
        eat(T_extern);
 
-       const char *linkage = parse_string_literals().begin;
+       source_position_t const pos     = *HERE;
+       char const       *const linkage = parse_string_literals().begin;
 
        linkage_kind_t old_linkage = current_linkage;
        linkage_kind_t new_linkage;
@@ -10704,7 +10536,7 @@ static void parse_linkage_specification(void)
        } else if (strcmp(linkage, "C++") == 0) {
                new_linkage = LINKAGE_CXX;
        } else {
-               errorf(HERE, "linkage string \"%s\" not recognized", linkage);
+               errorf(&pos, "linkage string \"%s\" not recognized", linkage);
                new_linkage = LINKAGE_INVALID;
        }
        current_linkage = new_linkage;
@@ -10782,23 +10614,17 @@ static void parse_externals(void)
 
        while (token.type != T_EOF && token.type != '}') {
 #ifndef NDEBUG
-               bool anchor_leak = false;
                for (int i = 0; i < T_LAST_TOKEN; ++i) {
                        unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
                        if (count != 0) {
                                /* the anchor set and its copy differs */
-                               errorf(HERE, "Leaked anchor token %k %d times", i, count);
-                               anchor_leak = true;
+                               internal_errorf(HERE, "Leaked anchor token %k %d times", i, count);
                        }
                }
                if (in_gcc_extension) {
                        /* an gcc extension scope was not closed */
-                       errorf(HERE, "Leaked __extension__");
-                       anchor_leak = true;
+                       internal_errorf(HERE, "Leaked __extension__");
                }
-
-               if (anchor_leak)
-                       abort();
 #endif
 
                parse_external();
@@ -10828,6 +10654,11 @@ static void parse_translation_unit(void)
        }
 }
 
+void set_default_visibility(elf_visibility_tag_t visibility)
+{
+       default_visibility = visibility;
+}
+
 /**
  * Parse the input.
  *
@@ -10880,17 +10711,15 @@ static void complete_incomplete_arrays(void)
 {
        size_t n = ARR_LEN(incomplete_arrays);
        for (size_t i = 0; i != n; ++i) {
-               declaration_t *const decl      = incomplete_arrays[i];
-               type_t        *const orig_type = decl->type;
-               type_t        *const type      = skip_typeref(orig_type);
+               declaration_t *const decl = incomplete_arrays[i];
+               type_t        *const type = skip_typeref(decl->type);
 
                if (!is_type_incomplete(type))
                        continue;
 
                if (warning.other) {
-                       warningf(&decl->base.source_position,
-                                       "array '%#T' assumed to have one element",
-                                       orig_type, decl->base.symbol);
+                       source_position_t const *const pos = &decl->base.source_position;
+                       warningf(pos, "array '%#N' assumed to have one element", (entity_t const*)decl);
                }
 
                type_t *const new_type = duplicate_type(type);