cleanup builtin handling and put it into an own file. Also implement a bunch of entit...
[cparser] / parser.c
index 97078ca..502dcc6 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -38,6 +38,7 @@
 #include "lang_features.h"
 #include "walk_statements.h"
 #include "warning.h"
+#include "printer.h"
 #include "adt/bitfiddle.h"
 #include "adt/error.h"
 #include "adt/array.h"
@@ -87,6 +88,7 @@ static scope_t             *file_scope        = NULL;
 static scope_t             *current_scope     = NULL;
 /** Point to the current function declaration if inside a function. */
 static function_t          *current_function  = NULL;
+static entity_t            *current_entity    = NULL;
 static entity_t            *current_init_decl = NULL;
 static switch_statement_t  *current_switch    = NULL;
 static statement_t         *current_loop      = NULL;
@@ -99,9 +101,9 @@ static label_statement_t   *label_first       = NULL;
 static label_statement_t  **label_anchor      = NULL;
 /** current translation unit. */
 static translation_unit_t  *unit              = NULL;
-/** true if we are in a type property context (evaluation only for type. */
+/** true if we are in a type property context (evaluation only for type) */
 static bool                 in_type_prop      = false;
-/** true in we are in a __extension__ context. */
+/** true if we are in an __extension__ context. */
 static bool                 in_gcc_extension  = false;
 static struct obstack       temp_obst;
 static entity_t            *anonymous_entity;
@@ -149,13 +151,8 @@ typedef enum declarator_flags_t {
 static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                   declarator_flags_t flags);
 
-static entity_t *record_entity(entity_t *entity, bool is_definition);
-
 static void semantic_comparison(binary_expression_t *expression);
 
-static void create_gnu_builtins(void);
-static void create_microsoft_intrinsics(void);
-
 #define STORAGE_CLASSES       \
        STORAGE_CLASSES_NO_EXTERN \
        case T_extern:
@@ -264,57 +261,6 @@ static void create_microsoft_intrinsics(void);
        case T_throw:                    \
        case T_true:
 
-/**
- * Allocate an AST node with given size and
- * initialize all fields with zero.
- */
-static void *allocate_ast_zero(size_t size)
-{
-       void *res = allocate_ast(size);
-       memset(res, 0, size);
-       return res;
-}
-
-/**
- * Returns the size of an entity node.
- *
- * @param kind  the entity kind
- */
-static size_t get_entity_struct_size(entity_kind_t kind)
-{
-       static const size_t sizes[] = {
-               [ENTITY_VARIABLE]        = sizeof(variable_t),
-               [ENTITY_PARAMETER]       = sizeof(parameter_t),
-               [ENTITY_COMPOUND_MEMBER] = sizeof(compound_member_t),
-               [ENTITY_FUNCTION]        = sizeof(function_t),
-               [ENTITY_TYPEDEF]         = sizeof(typedef_t),
-               [ENTITY_STRUCT]          = sizeof(compound_t),
-               [ENTITY_UNION]           = sizeof(compound_t),
-               [ENTITY_ENUM]            = sizeof(enum_t),
-               [ENTITY_ENUM_VALUE]      = sizeof(enum_value_t),
-               [ENTITY_LABEL]           = sizeof(label_t),
-               [ENTITY_LOCAL_LABEL]     = sizeof(label_t),
-               [ENTITY_NAMESPACE]       = sizeof(namespace_t)
-       };
-       assert(kind < lengthof(sizes));
-       assert(sizes[kind] != 0);
-       return sizes[kind];
-}
-
-/**
- * Allocate an entity of given kind and initialize all
- * fields with zero.
- *
- * @param kind   the kind of the entity to allocate
- */
-static entity_t *allocate_entity_zero(entity_kind_t kind)
-{
-       size_t    size   = get_entity_struct_size(kind);
-       entity_t *entity = allocate_ast_zero(size);
-       entity->kind     = kind;
-       return entity;
-}
-
 /**
  * Returns the size of a statement node.
  *
@@ -453,53 +399,10 @@ static statement_t *create_empty_statement(void)
        return allocate_statement_zero(STATEMENT_EMPTY);
 }
 
-/**
- * Returns the size of a type node.
- *
- * @param kind  the type kind
- */
-static size_t get_type_struct_size(type_kind_t kind)
-{
-       static const size_t sizes[] = {
-               [TYPE_ATOMIC]          = sizeof(atomic_type_t),
-               [TYPE_COMPLEX]         = sizeof(complex_type_t),
-               [TYPE_IMAGINARY]       = sizeof(imaginary_type_t),
-               [TYPE_BITFIELD]        = sizeof(bitfield_type_t),
-               [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t),
-               [TYPE_COMPOUND_UNION]  = sizeof(compound_type_t),
-               [TYPE_ENUM]            = sizeof(enum_type_t),
-               [TYPE_FUNCTION]        = sizeof(function_type_t),
-               [TYPE_POINTER]         = sizeof(pointer_type_t),
-               [TYPE_ARRAY]           = sizeof(array_type_t),
-               [TYPE_BUILTIN]         = sizeof(builtin_type_t),
-               [TYPE_TYPEDEF]         = sizeof(typedef_type_t),
-               [TYPE_TYPEOF]          = sizeof(typeof_type_t),
-       };
-       assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1);
-       assert(kind <= TYPE_TYPEOF);
-       assert(sizes[kind] != 0);
-       return sizes[kind];
-}
-
-/**
- * Allocate a type node of given kind and initialize all
- * fields with zero.
- *
- * @param kind             type kind to allocate
- */
-static type_t *allocate_type_zero(type_kind_t kind)
-{
-       size_t  size = get_type_struct_size(kind);
-       type_t *res  = obstack_alloc(type_obst, size);
-       memset(res, 0, size);
-       res->base.kind = kind;
-
-       return res;
-}
-
 static function_parameter_t *allocate_parameter(type_t *const type)
 {
-       function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param));
+       function_parameter_t *const param
+               = obstack_alloc(type_obst, sizeof(*param));
        memset(param, 0, sizeof(*param));
        param->type = type;
        return param;
@@ -569,6 +472,16 @@ static inline void next_token(void)
 #endif
 }
 
+static inline bool next_if(int const type)
+{
+       if (token.type == type) {
+               next_token();
+               return true;
+       } else {
+               return false;
+       }
+}
+
 /**
  * Return the next token with a given lookahead.
  */
@@ -702,8 +615,7 @@ static void eat_until_anchor(void)
 static void eat_block(void)
 {
        eat_until_matching_token('{');
-       if (token.type == '}')
-               next_token();
+       next_if('}');
 }
 
 #define eat(token_type) (assert(token.type == (token_type)), next_token())
@@ -747,8 +659,7 @@ static void type_error_incompatible(const char *msg,
                        parse_error_expected(NULL, (expected), NULL); \
                        add_anchor_token(expected);                   \
                        eat_until_anchor();                           \
-                       if (token.type == expected)                   \
-                               next_token();                             \
+                       next_if((expected));                          \
                        rem_anchor_token(expected);                   \
                        goto error_label;                             \
                }                                                 \
@@ -1242,12 +1153,9 @@ static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
  */
 static attribute_argument_t *parse_attribute_arguments(void)
 {
-       if (token.type == ')')
-               return NULL;
-
-       attribute_argument_t *first = NULL;
-       attribute_argument_t *last  = NULL;
-       while (true) {
+       attribute_argument_t  *first  = NULL;
+       attribute_argument_t **anchor = &first;
+       if (token.type != ')') do {
                attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument));
 
                /* is it an identifier */
@@ -1266,20 +1174,10 @@ static attribute_argument_t *parse_attribute_arguments(void)
                }
 
                /* append argument */
-               if (last == NULL) {
-                       first = argument;
-               } else {
-                       last->next = argument;
-               }
-               last = argument;
-
-               if (token.type == ',') {
-                       next_token();
-                       continue;
-               }
-               expect(')', end_error);
-               break;
-       }
+               *anchor = argument;
+               anchor  = &argument->next;
+       } while (next_if(','));
+       expect(')', end_error);
 
        return first;
 
@@ -1373,10 +1271,8 @@ static attribute_t *parse_attribute_gnu_single(void)
        attribute_t *attribute = allocate_attribute_zero(kind);
 
        /* parse arguments */
-       if (token.type == '(') {
-               next_token();
+       if (next_if('('))
                attribute->a.arguments = parse_attribute_arguments();
-       }
 
        return attribute;
 
@@ -1386,37 +1282,22 @@ end_error:
 
 static attribute_t *parse_attribute_gnu(void)
 {
-       attribute_t *first = NULL;
-       attribute_t *last  = NULL;
+       attribute_t  *first  = NULL;
+       attribute_t **anchor = &first;
 
        eat(T___attribute__);
        expect('(', end_error);
        expect('(', end_error);
 
-       if (token.type == ')') {
-               next_token();
-               expect(')', end_error);
-               return first;
-       }
-
-       while (true) {
+       if (token.type != ')') do {
                attribute_t *attribute = parse_attribute_gnu_single();
                if (attribute == NULL)
                        goto end_error;
 
-               if (last == NULL) {
-                       first = attribute;
-               } else {
-                       last->next = attribute;
-               }
-               last = attribute;
-
-               if (token.type == ')') {
-                       next_token();
-                       break;
-               }
-               expect(',', end_error);
-       }
+               *anchor = attribute;
+               anchor  = &attribute->next;
+       } while (next_if(','));
+       expect(')', end_error);
        expect(')', end_error);
 
 end_error:
@@ -1426,12 +1307,10 @@ end_error:
 /** Parse attributes. */
 static attribute_t *parse_attributes(attribute_t *first)
 {
-       attribute_t *last = first;
-       while (true) {
-               if (last != NULL) {
-                       while (last->next != NULL)
-                               last = last->next;
-               }
+       attribute_t **anchor = &first;
+       for (;;) {
+               while (*anchor != NULL)
+                       anchor = &(*anchor)->next;
 
                attribute_t *attribute;
                switch (token.type) {
@@ -1475,12 +1354,8 @@ static attribute_t *parse_attributes(attribute_t *first)
                        return first;
                }
 
-               if (last == NULL) {
-                       first = attribute;
-               } else {
-                       last->next = attribute;
-               }
-               last = attribute;
+               *anchor = attribute;
+               anchor  = &attribute->next;
        }
 }
 
@@ -1721,10 +1596,10 @@ unary:
 
 static designator_t *parse_designation(void)
 {
-       designator_t *result = NULL;
-       designator_t *last   = NULL;
+       designator_t  *result = NULL;
+       designator_t **anchor = &result;
 
-       while (true) {
+       for (;;) {
                designator_t *designator;
                switch (token.type) {
                case '[':
@@ -1754,12 +1629,8 @@ static designator_t *parse_designation(void)
                }
 
                assert(designator != NULL);
-               if (last != NULL) {
-                       last->next = designator;
-               } else {
-                       result = designator;
-               }
-               last = designator;
+               *anchor = designator;
+               anchor  = &designator->next;
        }
 end_error:
        return NULL;
@@ -1864,13 +1735,12 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 {
        /* there might be extra {} hierarchies */
        int braces = 0;
-       if (token.type == '{') {
+       if (next_if('{')) {
                if (warning.other)
                        warningf(HERE, "extra curly braces around scalar initializer");
                do {
                        ++braces;
-                       next_token();
-               } while (token.type == '{');
+               } while (next_if('{'));
        }
 
        expression_t *expression = parse_assignment_expression();
@@ -1893,9 +1763,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 
        bool additional_warning_displayed = false;
        while (braces > 0) {
-               if (token.type == ',') {
-                       next_token();
-               }
+               next_if(',');
                if (token.type != '}') {
                        if (!additional_warning_displayed && warning.other) {
                                warningf(HERE, "additional elements in scalar initializer");
@@ -2193,8 +2061,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
  */
 static void skip_initializers(void)
 {
-       if (token.type == '{')
-               next_token();
+       next_if('{');
 
        while (token.type != '}') {
                if (token.type == T_EOF)
@@ -2311,6 +2178,8 @@ finish_designator:
 
                        if (type == NULL) {
                                /* we are already outside, ... */
+                               if (outer_type == NULL)
+                                       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) {
@@ -2325,9 +2194,7 @@ finish_designator:
                                        && outer_type != NULL) {
                                sub = initializer_from_expression(outer_type, expression);
                                if (sub != NULL) {
-                                       if (token.type == ',') {
-                                               next_token();
-                                       }
+                                       next_if(',');
                                        if (token.type != '}' && warning.other) {
                                                warningf(HERE, "excessive elements in initializer for type '%T'",
                                                                 orig_type);
@@ -2515,17 +2382,14 @@ static void append_entity(scope_t *scope, entity_t *entity)
        } else {
                scope->entities = entity;
        }
-       scope->last_entity = entity;
+       entity->base.parent_entity = current_entity;
+       scope->last_entity         = entity;
 }
 
 
 static compound_t *parse_compound_type_specifier(bool is_struct)
 {
-       if (is_struct) {
-               eat(T_struct);
-       } else {
-               eat(T_union);
-       }
+       eat(is_struct ? T_struct : T_union);
 
        symbol_t    *symbol   = NULL;
        compound_t  *compound = NULL;
@@ -2627,8 +2491,7 @@ static void parse_enum_entries(type_t *const enum_type)
                entity->base.source_position = token.source_position;
                next_token();
 
-               if (token.type == '=') {
-                       next_token();
+               if (next_if('=')) {
                        expression_t *value = parse_constant_expression();
 
                        value = create_implicit_cast(value, enum_type);
@@ -2638,11 +2501,7 @@ static void parse_enum_entries(type_t *const enum_type)
                }
 
                record_entity(entity, false);
-
-               if (token.type != ',')
-                       break;
-               next_token();
-       } while (token.type != '}');
+       } while (next_if(',') && token.type != '}');
        rem_anchor_token('}');
 
        expect('}', end_error);
@@ -2653,33 +2512,38 @@ end_error:
 
 static type_t *parse_enum_specifier(void)
 {
-       entity_t        *entity;
-       symbol_t        *symbol;
+       entity_t *entity;
+       symbol_t *symbol;
 
        eat(T_enum);
-       if (token.type == T_IDENTIFIER) {
-               symbol = token.v.symbol;
-               next_token();
+       switch (token.type) {
+               case T_IDENTIFIER:
+                       symbol = token.v.symbol;
+                       next_token();
 
-               entity = get_tag(symbol, ENTITY_ENUM);
-               if (entity != NULL) {
-                       if (entity->base.parent_scope != current_scope &&
-                                       (token.type == '{' || token.type == ';')) {
-                               /* we're in an inner scope and have a definition. Shadow
-                                * existing definition in outer scope */
-                               entity = NULL;
-                       } else if (entity->enume.complete && token.type == '{') {
-                               errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
-                                               symbol, &entity->base.source_position);
+                       entity = get_tag(symbol, ENTITY_ENUM);
+                       if (entity != NULL) {
+                               if (entity->base.parent_scope != current_scope &&
+                                               (token.type == '{' || token.type == ';')) {
+                                       /* we're in an inner scope and have a definition. Shadow
+                                        * existing definition in outer scope */
+                                       entity = NULL;
+                               } else if (entity->enume.complete && token.type == '{') {
+                                       errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
+                                                       symbol, &entity->base.source_position);
+                               }
                        }
-               }
-       } else if (token.type != '{') {
-               parse_error_expected("while parsing enum type specifier",
-                                    T_IDENTIFIER, '{', NULL);
-               return NULL;
-       } else {
-               entity  = NULL;
-               symbol  = NULL;
+                       break;
+
+               case '{':
+                       entity = NULL;
+                       symbol = NULL;
+                       break;
+
+               default:
+                       parse_error_expected("while parsing enum type specifier",
+                                       T_IDENTIFIER, '{', NULL);
+                       return NULL;
        }
 
        if (entity == NULL) {
@@ -2741,9 +2605,8 @@ static type_t *parse_typeof(void)
        bool old_gcc_extension = in_gcc_extension;
        in_type_prop           = true;
 
-       while (token.type == T___extension__) {
+       while (next_if(T___extension__)) {
                /* This can be a prefix to a typename or an expression. */
-               next_token();
                in_gcc_extension = true;
        }
        switch (token.type) {
@@ -2830,7 +2693,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
        attribute_property_argument_t *property
                = allocate_ast_zero(sizeof(*property));
 
-       while (true) {
+       do {
                if (token.type != T_IDENTIFIER) {
                        parse_error_expected("while parsing property declspec",
                                             T_IDENTIFIER, NULL);
@@ -2860,10 +2723,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
                        property->get_symbol = token.v.symbol;
                }
                next_token();
-               if (token.type == ')')
-                       break;
-               expect(',', end_error);
-       }
+       } while (next_if(','));
 
        attribute->a.property = property;
 
@@ -2876,9 +2736,8 @@ end_error:
 static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
 {
        attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
-       if (token.type == T_restrict) {
+       if (next_if(T_restrict)) {
                kind = ATTRIBUTE_MS_RESTRICT;
-               next_token();
        } else if (token.type == T_IDENTIFIER) {
                const char *name = token.v.symbol->string;
                next_token();
@@ -2906,10 +2765,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
        }
 
        /* parse arguments */
-       if (token.type == '(') {
-               next_token();
+       if (next_if('('))
                attribute->a.arguments = parse_attribute_arguments();
-       }
 
        return attribute;
 }
@@ -2920,37 +2777,24 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 
        expect('(', end_error);
 
-       if (token.type == ')') {
-               next_token();
+       if (next_if(')'))
                return NULL;
-       }
 
        add_anchor_token(')');
 
-       attribute_t *last = first;
-       while (true) {
-               if (last != NULL) {
-                       while (last->next != NULL)
-                               last = last->next;
-               }
+       attribute_t **anchor = &first;
+       do {
+               while (*anchor != NULL)
+                       anchor = &(*anchor)->next;
 
                attribute_t *attribute
                        = parse_microsoft_extended_decl_modifier_single();
                if (attribute == NULL)
                        goto end_error;
 
-               if (last == NULL) {
-                       first = attribute;
-               } else {
-                       last->next = attribute;
-               }
-               last = attribute;
-
-               if (token.type == ')') {
-                       break;
-               }
-               expect(',', end_error);
-       }
+               *anchor = attribute;
+               anchor  = &attribute->next;
+       } while (next_if(','));
 
        rem_anchor_token(')');
        expect(')', end_error);
@@ -3412,7 +3256,6 @@ warn_about_long_long:
 
 end_error:
        specifiers->type = type_error_type;
-       return;
 }
 
 static type_qualifiers_t parse_type_qualifiers(void)
@@ -3453,12 +3296,7 @@ static void parse_identifier_list(scope_t *scope)
 
                if (scope != NULL)
                        append_entity(scope, entity);
-
-               if (token.type != ',') {
-                       break;
-               }
-               next_token();
-       } while (token.type == T_IDENTIFIER);
+       } while (next_if(',') && token.type == T_IDENTIFIER);
 }
 
 static entity_t *parse_parameter(void)
@@ -3539,7 +3377,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
 
        if (has_parameters()) {
                function_parameter_t **anchor = &type->parameters;
-               for (;;) {
+               do {
                        switch (token.type) {
                        case T_DOTDOTDOT:
                                next_token();
@@ -3575,11 +3413,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                        default:
                                goto parameters_finished;
                        }
-                       if (token.type != ',') {
-                               goto parameters_finished;
-                       }
-                       next_token();
-               }
+               } while (next_if(','));
        }
 
 
@@ -3673,18 +3507,12 @@ static construct_type_t *parse_array_declarator(void)
        memset(array, 0, sizeof(*array));
        cons->kind = CONSTRUCT_ARRAY;
 
-       if (token.type == T_static) {
+       if (next_if(T_static))
                array->is_static = true;
-               next_token();
-       }
 
        type_qualifiers_t type_qualifiers = parse_type_qualifiers();
-       if (type_qualifiers != 0) {
-               if (token.type == T_static) {
+       if (type_qualifiers != 0 && next_if(T_static))
                        array->is_static = true;
-                       next_token();
-               }
-       }
        array->type_qualifiers = type_qualifiers;
 
        if (token.type == '*' && look_ahead(1)->type == ']') {
@@ -3762,26 +3590,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
                                break;
 
                        case T__based: {
-#if 0
-                               source_position_t const pos = *HERE;
-                               next_token();
-                               expect('(', end_error);
-                               add_anchor_token(')');
-                               based = parse_microsoft_based();
-                               rem_anchor_token(')');
-                               expect(')', end_error);
-                               if (token.type != '*') {
-                                       if (token.type == T__based) {
-                                               errorf(&pos, "__based type modifier specified more than once");
-                                       } else if (warning.other) {
-                                               warningf(&pos,
-                                                               "__based does not precede a pointer declarator, ignored");
-                                       }
-                                       continue;
-                               }
-#else
-                               panic("based currently disabled");
-#endif
+                               panic("based not supported anymore");
                                /* FALLTHROUGH */
                        }
 
@@ -3801,11 +3610,6 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
        }
 
 ptr_operator_end: ;
-#if 0
-       modifiers      |= env->modifiers;
-       env->modifiers  = modifiers;
-#endif
-
        construct_type_t *inner_types = NULL;
 
        switch (token.type) {
@@ -3880,7 +3684,8 @@ end_error:
        return NULL;
 }
 
-static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
+static type_t *construct_declarator_type(construct_type_t *construct_list,
+                                         type_t *type)
 {
        construct_type_t *iter = construct_list;
        for (; iter != NULL; iter = iter->base.next) {
@@ -4039,15 +3844,11 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        attribute_t *attributes = parse_attributes(env.attributes);
        /* append (shared) specifier attribute behind attributes of this
-          declarator */
-       if (attributes != NULL) {
-               attribute_t *last = attributes;
-               while (last->next != NULL)
-                       last = last->next;
-               last->next = specifiers->attributes;
-       } else {
-               attributes = specifiers->attributes;
-       }
+        * declarator */
+       attribute_t **anchor = &attributes;
+       while (*anchor != NULL)
+               anchor = &(*anchor)->next;
+       *anchor = specifiers->attributes;
 
        entity_t *entity;
        if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
@@ -4275,11 +4076,52 @@ static bool is_error_entity(entity_t *const ent)
        return false;
 }
 
+static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
+{
+       for (const attribute_t *tattr = list; tattr != NULL; tattr = tattr->next) {
+               if (attributes_equal(tattr, attr))
+                       return true;
+       }
+       return false;
+}
+
+/**
+ * test wether new_list contains any attributes not included in old_list
+ */
+static bool has_new_attributes(const attribute_t *old_list,
+                               const attribute_t *new_list)
+{
+       for (const attribute_t *attr = new_list; attr != NULL; attr = attr->next) {
+               if (!contains_attribute(old_list, attr))
+                       return true;
+       }
+       return false;
+}
+
+/**
+ * Merge in attributes from an attribute list (probably from a previous
+ * declaration with the same name). Warning: destroys the old structure
+ * of the attribute list - don't reuse attributes after this call.
+ */
+static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
+{
+       attribute_t *next;
+       for (attribute_t *attr = attributes; attr != NULL; attr = next) {
+               next = attr->next;
+               if (contains_attribute(decl->attributes, attr))
+                       continue;
+
+               /* move attribute to new declarations attributes list */
+               attr->next       = decl->attributes;
+               decl->attributes = attr;
+       }
+}
+
 /**
  * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
  * for various problems that occur for multiple definitions
  */
-static entity_t *record_entity(entity_t *entity, const bool is_definition)
+entity_t *record_entity(entity_t *entity, const bool is_definition)
 {
        const symbol_t *const    symbol  = entity->base.symbol;
        const namespace_tag_t    namespc = (namespace_tag_t)entity->base.namespc;
@@ -4429,22 +4271,28 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                                if (old_storage_class == STORAGE_CLASS_EXTERN &&
                                                new_storage_class == STORAGE_CLASS_EXTERN) {
-warn_redundant_declaration:
-                                       if (!is_definition           &&
+
+warn_redundant_declaration: ;
+                                       bool has_new_attrs
+                                               = has_new_attributes(prev_decl->attributes,
+                                                                    decl->attributes);
+                                       if (has_new_attrs) {
+                                               merge_in_attributes(decl, prev_decl->attributes);
+                                       } 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);
+                                                        "redundant declaration for '%Y' (declared %P)",
+                                                        symbol, &previous_entity->base.source_position);
                                        }
                                } 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);
+                                                      "static declaration of '%Y' follows non-static declaration (declared %P)",
+                                                      symbol, &previous_entity->base.source_position);
                                        } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
                                                prev_decl->storage_class          = STORAGE_CLASS_NONE;
                                                prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
@@ -4678,9 +4526,8 @@ static void parse_declaration_rest(entity_t *ndeclaration,
 
                check_variable_type_complete(entity);
 
-               if (token.type != ',')
+               if (!next_if(','))
                        break;
-               eat(',');
 
                add_anchor_token('=');
                ndeclaration = parse_declarator(specifiers, flags);
@@ -5269,9 +5116,8 @@ static void check_reachable(statement_t *const stmt)
                        break;
                }
 
-               case STATEMENT_CONTINUE: {
-                       statement_t *parent = stmt;
-                       for (;;) {
+               case STATEMENT_CONTINUE:
+                       for (statement_t *parent = stmt;;) {
                                parent = parent->base.parent;
                                if (parent == NULL) /* continue not within loop */
                                        return;
@@ -5285,11 +5131,9 @@ static void check_reachable(statement_t *const stmt)
                                        default: break;
                                }
                        }
-               }
 
-               case STATEMENT_BREAK: {
-                       statement_t *parent = stmt;
-                       for (;;) {
+               case STATEMENT_BREAK:
+                       for (statement_t *parent = stmt;;) {
                                parent = parent->base.parent;
                                if (parent == NULL) /* break not within loop/switch */
                                        return;
@@ -5308,7 +5152,6 @@ static void check_reachable(statement_t *const stmt)
                        }
 found_break_parent:
                        break;
-               }
 
                case STATEMENT_GOTO:
                        if (stmt->gotos.expression) {
@@ -5749,7 +5592,9 @@ static void parse_external_declaration(void)
                /* parse function body */
                int         label_stack_top      = label_top();
                function_t *old_current_function = current_function;
+               entity_t   *old_current_entity   = current_entity;
                current_function                 = function;
+               current_entity                   = (entity_t*) function;
                current_parent                   = NULL;
 
                goto_first   = NULL;
@@ -5781,6 +5626,8 @@ static void parse_external_declaration(void)
 
                assert(current_parent   == NULL);
                assert(current_function == function);
+               assert(current_entity   == (entity_t*) function);
+               current_entity   = old_current_entity;
                current_function = old_current_function;
                label_pop_to(label_stack_top);
        }
@@ -5803,7 +5650,7 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *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);
+                      base_type);
                bit_size = 0;
        } else {
                bit_size = get_type_size(base_type) * 8;
@@ -5949,7 +5796,7 @@ static expression_t *find_create_select(const source_position_t *pos,
 static void parse_compound_declarators(compound_t *compound,
                const declaration_specifiers_t *specifiers)
 {
-       while (true) {
+       do {
                entity_t *entity;
 
                if (token.type == ':') {
@@ -5962,15 +5809,11 @@ static void parse_compound_declarators(compound_t *compound,
                        type_t *type = make_bitfield_type(base_type, size,
                                        &source_position, NULL);
 
-                       attribute_t *attributes = parse_attributes(NULL);
-                       if (attributes != NULL) {
-                               attribute_t *last = attributes;
-                               while (last->next != NULL)
-                                       last = last->next;
-                               last->next = specifiers->attributes;
-                       } else {
-                               attributes = specifiers->attributes;
-                       }
+                       attribute_t  *attributes = parse_attributes(NULL);
+                       attribute_t **anchor     = &attributes;
+                       while (*anchor != NULL)
+                               anchor = &(*anchor)->next;
+                       *anchor = specifiers->attributes;
 
                        entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
                        entity->base.namespc                       = NAMESPACE_NORMAL;
@@ -6021,7 +5864,7 @@ static void parse_compound_declarators(compound_t *compound,
                                        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'",
+                                                      "compound member '%Y' must not have function type '%T'",
                                                                entity->base.symbol, orig_type);
                                        } else if (is_type_incomplete(type)) {
                                                /* §6.7.2.1:16 flexible array member */
@@ -6029,7 +5872,7 @@ static void parse_compound_declarators(compound_t *compound,
                                                                token.type          != ';' ||
                                                                look_ahead(1)->type != '}') {
                                                        errorf(&entity->base.source_position,
-                                                                       "compound member '%Y' has incomplete type '%T'",
+                                                              "compound member '%Y' has incomplete type '%T'",
                                                                        entity->base.symbol, orig_type);
                                                }
                                        }
@@ -6038,11 +5881,7 @@ static void parse_compound_declarators(compound_t *compound,
                                append_entity(&compound->members, entity);
                        }
                }
-
-               if (token.type != ',')
-                       break;
-               next_token();
-       }
+       } while (next_if(','));
        expect(';', end_error);
 
 end_error:
@@ -6077,8 +5916,8 @@ static type_t *parse_typename(void)
        declaration_specifiers_t specifiers;
        memset(&specifiers, 0, sizeof(specifiers));
        parse_declaration_specifiers(&specifiers);
-       if (specifiers.storage_class != STORAGE_CLASS_NONE ||
-                       specifiers.thread_local) {
+       if (specifiers.storage_class != STORAGE_CLASS_NONE
+                       || specifiers.thread_local) {
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
@@ -6280,91 +6119,6 @@ static entity_t *create_implicit_function(symbol_t *symbol,
        return entity;
 }
 
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- */
-static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1,
-                                    type_t *argument_type2)
-{
-       function_parameter_t *const parameter2 = allocate_parameter(argument_type2);
-       function_parameter_t *const parameter1 = allocate_parameter(argument_type1);
-       parameter1->next = parameter2;
-
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = parameter1;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- *
- * @param return_type    the return type
- * @param argument_type  the argument type
- */
-static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
-{
-       function_parameter_t *const parameter = allocate_parameter(argument_type);
-
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = parameter;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type, ...) function type if not
- * already exists.
- *
- * @param return_type    the return type
- * @param argument_type  the argument type
- */
-static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type)
-{
-       function_parameter_t *const parameter = allocate_parameter(argument_type);
-
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = parameter;
-       type->function.variadic    = true;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type    the return type
- */
-static type_t *make_function_0_type(type_t *return_type)
-{
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = NULL;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a NO_RETURN return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type    the return type
- */
-static type_t *make_function_0_type_noreturn(type_t *return_type)
-{
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = NULL;
-       type->function.modifiers  |= DM_NORETURN;
-       return identify_new_type(type);
-}
-
 /**
  * Performs automatic type cast as described in §6.3.2.1.
  *
@@ -6473,13 +6227,12 @@ static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol,
 static entity_t *parse_qualified_identifier(void)
 {
        /* namespace containing the symbol */
-       symbol_t      *symbol;
-       const scope_t *lookup_scope = NULL;
+       symbol_t          *symbol;
+       source_position_t  pos;
+       const scope_t     *lookup_scope = NULL;
 
-       if (token.type == T_COLONCOLON) {
-               next_token();
+       if (next_if(T_COLONCOLON))
                lookup_scope = &unit->scope;
-       }
 
        entity_t *entity;
        while (true) {
@@ -6488,14 +6241,14 @@ static entity_t *parse_qualified_identifier(void)
                        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
                }
                symbol = token.v.symbol;
+               pos    = *HERE;
                next_token();
 
                /* lookup entity */
                entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
 
-               if (token.type != T_COLONCOLON)
+               if (!next_if(T_COLONCOLON))
                        break;
-               next_token();
 
                switch (entity->kind) {
                case ENTITY_NAMESPACE:
@@ -6507,7 +6260,7 @@ static entity_t *parse_qualified_identifier(void)
                        lookup_scope = &entity->compound.members;
                        break;
                default:
-                       errorf(HERE, "'%Y' must be a namespace, class, struct or union (but is a %s)",
+                       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;
                }
@@ -6517,14 +6270,14 @@ static entity_t *parse_qualified_identifier(void)
                if (!strict_mode && token.type == '(') {
                        /* an implicitly declared function */
                        if (warning.error_implicit_function_declaration) {
-                               errorf(HERE, "implicit declaration of function '%Y'", symbol);
+                               errorf(&pos, "implicit declaration of function '%Y'", symbol);
                        } else if (warning.implicit_function_declaration) {
-                               warningf(HERE, "implicit declaration of function '%Y'", symbol);
+                               warningf(&pos, "implicit declaration of function '%Y'", symbol);
                        }
 
-                       entity = create_implicit_function(symbol, HERE);
+                       entity = create_implicit_function(symbol, &pos);
                } else {
-                       errorf(HERE, "unknown identifier '%Y' found.", symbol);
+                       errorf(&pos, "unknown identifier '%Y' found.", symbol);
                        entity = create_error_entity(symbol, ENTITY_VARIABLE);
                }
        }
@@ -6533,12 +6286,7 @@ static entity_t *parse_qualified_identifier(void)
 
 end_error:
        /* skip further qualifications */
-       while (token.type == T_IDENTIFIER) {
-               next_token();
-               if (token.type != T_COLONCOLON)
-                       break;
-               next_token();
-       }
+       while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
 
        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
 }
@@ -6574,8 +6322,9 @@ static expression_t *parse_reference(void)
        }
 
        if (entity->base.parent_scope != file_scope
-               && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth)
-               && is_type_valid(orig_type) && !is_type_function(orig_type)) {
+               && (current_function != NULL
+                       && entity->base.parent_scope->depth < current_function->parameters.depth)
+               && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) {
                if (entity->kind == ENTITY_VARIABLE) {
                        /* access of a variable from an outer function */
                        entity->variable.address_taken = true;
@@ -6840,8 +6589,7 @@ static designator_t *parse_designator(void)
 
        designator_t *last_designator = result;
        while (true) {
-               if (token.type == '.') {
-                       next_token();
+               if (next_if('.')) {
                        if (token.type != T_IDENTIFIER) {
                                parse_error_expected("while parsing member designator",
                                                     T_IDENTIFIER, NULL);
@@ -6856,8 +6604,7 @@ static designator_t *parse_designator(void)
                        last_designator       = designator;
                        continue;
                }
-               if (token.type == '[') {
-                       next_token();
+               if (next_if('[')) {
                        add_anchor_token(']');
                        designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
                        designator->source_position = *HERE;
@@ -7220,14 +6967,9 @@ static expression_t *parse_noop_expression(void)
                add_anchor_token(')');
                add_anchor_token(',');
 
-               if (token.type != ')') {
-                       while (true) {
-                               (void)parse_assignment_expression();
-                               if (token.type != ',')
-                                       break;
-                               next_token();
-                       }
-               }
+               if (token.type != ')') do {
+                       (void)parse_assignment_expression();
+               } while (next_if(','));
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
@@ -7627,17 +7369,13 @@ static expression_t *parse_call_expression(expression_t *expression)
 
        if (token.type != ')') {
                call_argument_t **anchor = &call->arguments;
-               for (;;) {
+               do {
                        call_argument_t *argument = allocate_ast_zero(sizeof(*argument));
                        argument->expression = parse_assignment_expression();
 
                        *anchor = argument;
                        anchor  = &argument->next;
-
-                       if (token.type != ',')
-                               break;
-                       next_token();
-               }
+               } while (next_if(','));
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
@@ -7953,8 +7691,7 @@ static expression_t *parse_delete(void)
 
        eat(T_delete);
 
-       if (token.type == '[') {
-               next_token();
+       if (next_if('[')) {
                result->kind = EXPR_UNARY_DELETE_ARRAY;
                expect(']', end_error);
 end_error:;
@@ -8062,14 +7799,14 @@ static bool is_lvalue(const expression_t *expression)
                return true;
 
        default: {
-         type_t *type = skip_typeref(expression->base.type);
-         return
-               /* ISO/IEC 14882:1998(E) §3.10:3 */
-               is_type_reference(type) ||
-               /* Claim it is an lvalue, if the type is invalid.  There was a parse
-                * error before, which maybe prevented properly recognizing it as
-                * lvalue. */
-               !is_type_valid(type);
+               type_t *type = skip_typeref(expression->base.type);
+               return
+                       /* ISO/IEC 14882:1998(E) §3.10:3 */
+                       is_type_reference(type) ||
+                       /* Claim it is an lvalue, if the type is invalid.  There was a parse
+                        * error before, which maybe prevented properly recognizing it as
+                        * lvalue. */
+                       !is_type_valid(type);
        }
        }
 }
@@ -9231,8 +8968,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
                memset(argument, 0, sizeof(argument[0]));
 
-               if (token.type == '[') {
-                       eat('[');
+               if (next_if('[')) {
                        if (token.type != T_IDENTIFIER) {
                                parse_error_expected("while parsing asm argument",
                                                     T_IDENTIFIER, NULL);
@@ -9311,9 +9047,8 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                *anchor = argument;
                anchor  = &argument->next;
 
-               if (token.type != ',')
+               if (!next_if(','))
                        break;
-               eat(',');
        }
 
        return result;
@@ -9326,23 +9061,18 @@ end_error:
  */
 static asm_clobber_t *parse_asm_clobbers(void)
 {
-       asm_clobber_t *result = NULL;
-       asm_clobber_t *last   = NULL;
+       asm_clobber_t *result  = NULL;
+       asm_clobber_t **anchor = &result;
 
        while (token.type == T_STRING_LITERAL) {
                asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
                clobber->clobber       = parse_string_literals();
 
-               if (last != NULL) {
-                       last->next = clobber;
-               } else {
-                       result = clobber;
-               }
-               last = clobber;
+               *anchor = clobber;
+               anchor  = &clobber->next;
 
-               if (token.type != ',')
+               if (!next_if(','))
                        break;
-               eat(',');
        }
 
        return result;
@@ -9358,36 +9088,31 @@ static statement_t *parse_asm_statement(void)
 
        eat(T_asm);
 
-       if (token.type == T_volatile) {
-               next_token();
+       if (next_if(T_volatile))
                asm_statement->is_volatile = true;
-       }
 
        expect('(', end_error);
        add_anchor_token(')');
        add_anchor_token(':');
        asm_statement->asm_text = parse_string_literals();
 
-       if (token.type != ':') {
+       if (!next_if(':')) {
                rem_anchor_token(':');
                goto end_of_asm;
        }
-       eat(':');
 
        asm_statement->outputs = parse_asm_arguments(true);
-       if (token.type != ':') {
+       if (!next_if(':')) {
                rem_anchor_token(':');
                goto end_of_asm;
        }
-       eat(':');
 
        asm_statement->inputs = parse_asm_arguments(false);
-       if (token.type != ':') {
+       if (!next_if(':')) {
                rem_anchor_token(':');
                goto end_of_asm;
        }
        rem_anchor_token(':');
-       eat(':');
 
        asm_statement->clobbers = parse_asm_clobbers();
 
@@ -9434,8 +9159,7 @@ static statement_t *parse_case_statement(void)
        }
 
        if (GNU_MODE) {
-               if (token.type == T_DOTDOTDOT) {
-                       next_token();
+               if (next_if(T_DOTDOTDOT)) {
                        expression_t *const end_range   = parse_expression();
                        statement->case_label.end_range = end_range;
                        if (!is_constant_expression(end_range)) {
@@ -9638,8 +9362,7 @@ end_error:
        statement->ifs.true_statement = true_stmt;
        rem_anchor_token(T_else);
 
-       if (token.type == T_else) {
-               next_token();
+       if (next_if(T_else)) {
                statement->ifs.false_statement = parse_statement();
        } else if (warning.parentheses &&
                        true_stmt->kind == STATEMENT_IF &&
@@ -9842,13 +9565,11 @@ static statement_t *parse_for(void)
        scope_t      *old_scope = scope_push(&statement->fors.scope);
 
        bool old_gcc_extension = in_gcc_extension;
-       while (token.type == T___extension__) {
-               next_token();
+       while (next_if(T___extension__)) {
                in_gcc_extension = true;
        }
 
-       if (token.type == ';') {
-               next_token();
+       if (next_if(';')) {
        } else if (is_declaration_specifier(&token, false)) {
                parse_declaration(record_entity, DECL_FLAGS_NONE);
        } else {
@@ -9916,8 +9637,7 @@ static statement_t *parse_goto(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
        eat(T_goto);
 
-       if (GNU_MODE && token.type == '*') {
-               next_token();
+       if (GNU_MODE && next_if('*')) {
                expression_t *expression = parse_expression();
                mark_vars_read(expression, NULL);
 
@@ -10200,8 +9920,7 @@ static statement_t *parse_ms_try_statment(void)
 
        POP_PARENT;
 
-       if (token.type == T___except) {
-               eat(T___except);
+       if (next_if(T___except)) {
                expect('(', end_error);
                add_anchor_token(')');
                expression_t *const expr = parse_expression();
@@ -10218,8 +9937,7 @@ static statement_t *parse_ms_try_statment(void)
                rem_anchor_token(')');
                expect(')', end_error);
                statement->ms_try.final_statement = parse_compound_statement(false);
-       } else if (token.type == T__finally) {
-               eat(T___finally);
+       } else if (next_if(T__finally)) {
                statement->ms_try.final_statement = parse_compound_statement(false);
        } else {
                parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
@@ -10248,7 +9966,7 @@ static statement_t *parse_local_label_declaration(void)
 
        entity_t *begin = NULL, *end = NULL;
 
-       while (true) {
+       do {
                if (token.type != T_IDENTIFIER) {
                        parse_error_expected("while parsing local label declaration",
                                T_IDENTIFIER, NULL);
@@ -10276,11 +9994,7 @@ static statement_t *parse_local_label_declaration(void)
                        environment_push(entity);
                }
                next_token();
-
-               if (token.type != ',')
-                       break;
-               next_token();
-       }
+       } while (next_if(','));
        eat(';');
 end_error:
        statement->declaration.declarations_begin = begin;
@@ -10300,9 +10014,9 @@ static void parse_namespace_definition(void)
                next_token();
 
                entity = get_entity(symbol, NAMESPACE_NORMAL);
-               if (entity       != NULL             &&
-                               entity->kind != ENTITY_NAMESPACE &&
-                               entity->base.parent_scope == current_scope) {
+               if (entity != NULL
+                               && entity->kind != ENTITY_NAMESPACE
+                               && entity->base.parent_scope == current_scope) {
                        if (!is_error_entity(entity)) {
                                error_redefined_as_different_kind(&token.source_position,
                                                entity, ENTITY_NAMESPACE);
@@ -10330,12 +10044,17 @@ static void parse_namespace_definition(void)
        size_t const  top       = environment_top();
        scope_t      *old_scope = scope_push(&entity->namespacee.members);
 
+       entity_t     *old_current_entity = current_entity;
+       current_entity = entity;
+
        expect('{', end_error);
        parse_externals();
        expect('}', end_error);
 
 end_error:
        assert(current_scope == &entity->namespacee.members);
+       assert(current_entity == entity);
+       current_entity = old_current_entity;
        scope_pop(old_scope);
        environment_pop_to(top);
 }
@@ -10387,9 +10106,7 @@ expression_statment:
        case T___extension__:
                /* This can be a prefix to a declaration or an expression statement.
                 * We simply eat it now and parse the rest with tail recursion. */
-               do {
-                       next_token();
-               } while (token.type == T___extension__);
+               while (next_if(T___extension__)) {}
                bool old_gcc_extension = in_gcc_extension;
                in_gcc_extension       = true;
                statement = intern_parse_statement();
@@ -10786,8 +10503,7 @@ static void parse_linkage_specification(void)
        }
        current_linkage = new_linkage;
 
-       if (token.type == '{') {
-               next_token();
+       if (next_if('{')) {
                parse_externals();
                expect('}', end_error);
        } else {
@@ -10916,8 +10632,7 @@ void start_parsing(void)
        error_count       = 0;
        warning_count     = 0;
 
-       type_set_output(stderr);
-       ast_set_output(stderr);
+       print_to_file(stderr);
 
        assert(unit == NULL);
        unit = allocate_ast_zero(sizeof(unit[0]));
@@ -11024,104 +10739,6 @@ void parse(void)
        incomplete_arrays = NULL;
 }
 
-/**
- * create a builtin function.
- */
-static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type)
-{
-       symbol_t *symbol = symbol_table_insert(name);
-       entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
-       entity->declaration.storage_class          = STORAGE_CLASS_EXTERN;
-       entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
-       entity->declaration.type                   = function_type;
-       entity->declaration.implicit               = true;
-       entity->base.symbol                        = symbol;
-       entity->base.source_position               = builtin_source_position;
-
-       entity->function.btk                       = kind;
-
-       record_entity(entity, /*is_definition=*/false);
-       return entity;
-}
-
-
-/**
- * Create predefined gnu builtins.
- */
-static void create_gnu_builtins(void)
-{
-#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b)
-
-       GNU_BUILTIN(alloca,         make_function_1_type(type_void_ptr, type_size_t));
-       GNU_BUILTIN(huge_val,       make_function_0_type(type_double));
-       GNU_BUILTIN(inf,            make_function_0_type(type_double));
-       GNU_BUILTIN(inff,           make_function_0_type(type_float));
-       GNU_BUILTIN(infl,           make_function_0_type(type_long_double));
-       GNU_BUILTIN(nan,            make_function_1_type(type_double, type_char_ptr));
-       GNU_BUILTIN(nanf,           make_function_1_type(type_float, type_char_ptr));
-       GNU_BUILTIN(nanl,           make_function_1_type(type_long_double, type_char_ptr));
-       GNU_BUILTIN(va_end,         make_function_1_type(type_void, type_valist));
-       GNU_BUILTIN(expect,         make_function_2_type(type_long, type_long, type_long));
-       GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int));
-       GNU_BUILTIN(frame_address,  make_function_1_type(type_void_ptr, type_unsigned_int));
-       GNU_BUILTIN(ffs,            make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(clz,            make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(ctz,            make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(popcount,       make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(parity,         make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(prefetch,       make_function_1_type_variadic(type_float, type_void_ptr));
-       GNU_BUILTIN(trap,           make_function_0_type_noreturn(type_void));
-
-#undef GNU_BUILTIN
-}
-
-/**
- * Create predefined MS intrinsics.
- */
-static void create_microsoft_intrinsics(void)
-{
-#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b)
-
-       /* intrinsics for all architectures */
-       MS_BUILTIN(_rotl,                  make_function_2_type(type_unsigned_int,   type_unsigned_int, type_int));
-       MS_BUILTIN(_rotr,                  make_function_2_type(type_unsigned_int,   type_unsigned_int, type_int));
-       MS_BUILTIN(_rotl64,                make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
-       MS_BUILTIN(_rotr64,                make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
-       MS_BUILTIN(_byteswap_ushort,       make_function_1_type(type_unsigned_short, type_unsigned_short));
-       MS_BUILTIN(_byteswap_ulong,        make_function_1_type(type_unsigned_long,  type_unsigned_long));
-       MS_BUILTIN(_byteswap_uint64,       make_function_1_type(type_unsigned_int64, type_unsigned_int64));
-
-       MS_BUILTIN(__debugbreak,            make_function_0_type(type_void));
-       MS_BUILTIN(_ReturnAddress,          make_function_0_type(type_void_ptr));
-       MS_BUILTIN(_AddressOfReturnAddress, make_function_0_type(type_void_ptr));
-       MS_BUILTIN(__popcount,              make_function_1_type(type_unsigned_int, type_unsigned_int));
-
-       /* x86/x64 only */
-       MS_BUILTIN(_enable,                make_function_0_type(type_void));
-       MS_BUILTIN(_disable,               make_function_0_type(type_void));
-       MS_BUILTIN(__inbyte,               make_function_1_type(type_unsigned_char, type_unsigned_short));
-       MS_BUILTIN(__inword,               make_function_1_type(type_unsigned_short, type_unsigned_short));
-       MS_BUILTIN(__indword,              make_function_1_type(type_unsigned_long, type_unsigned_short));
-       MS_BUILTIN(__outbyte,              make_function_2_type(type_void, type_unsigned_short, type_unsigned_char));
-       MS_BUILTIN(__outword,              make_function_2_type(type_void, type_unsigned_short, type_unsigned_short));
-       MS_BUILTIN(__outdword,             make_function_2_type(type_void, type_unsigned_short, type_unsigned_long));
-       MS_BUILTIN(__ud2,                  make_function_0_type_noreturn(type_void));
-       MS_BUILTIN(_BitScanForward,        make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
-       MS_BUILTIN(_BitScanReverse,        make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
-       MS_BUILTIN(_InterlockedExchange,   make_function_2_type(type_long, type_long_ptr, type_long));
-       MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64));
-
-       if (machine_size <= 32) {
-               MS_BUILTIN(__readeflags,           make_function_0_type(type_unsigned_int));
-               MS_BUILTIN(__writeeflags,          make_function_1_type(type_void, type_unsigned_int));
-       } else {
-               MS_BUILTIN(__readeflags,           make_function_0_type(type_unsigned_int64));
-               MS_BUILTIN(__writeeflags,          make_function_1_type(type_void, type_unsigned_int64));
-       }
-
-#undef MS_BUILTIN
-}
-
 /**
  * Initialize the parser.
  */