If a K&R function definition has a variadic prototype earlier, then make the function...
[cparser] / parser.c
index 8a906f9..d05ec2a 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1,6 +1,6 @@
 /*
  * This file is part of cparser.
- * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
+ * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -58,7 +58,6 @@ struct declaration_specifiers_t {
        unsigned char      alignment;         /**< Alignment, 0 if not set. */
        bool               is_inline    : 1;
        bool               thread_local : 1;  /**< GCC __thread */
-       bool               deprecated   : 1;
        attribute_t       *attributes;        /**< list of attributes */
        type_t            *type;
 };
@@ -1002,7 +1001,7 @@ static bool is_null_pointer_constant(const expression_t *expression)
        return
                is_type_integer(type)              &&
                is_constant_expression(expression) &&
-               fold_constant(expression) == 0;
+               !fold_constant_to_bool(expression);
 }
 
 /**
@@ -1307,6 +1306,7 @@ static symbol_t *get_symbol_from_token(void)
 {
        switch(token.type) {
        case T_IDENTIFIER:
+               return token.v.symbol;
        case T_auto:
        case T_char:
        case T_double:
@@ -1336,7 +1336,7 @@ static symbol_t *get_symbol_from_token(void)
        case T_volatile:
        case T_inline:
                /* maybe we need more tokens ... add them on demand */
-               return token.v.symbol;
+               return get_token_symbol(&token);
        default:
                return NULL;
        }
@@ -1840,11 +1840,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                            &expression->base.source_position);
 
        initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
-#if 0
-       if (type->kind == TYPE_BITFIELD) {
-               type = type->bitfield.base_type;
-       }
-#endif
        result->value.value = create_implicit_cast(expression, type);
 
        return result;
@@ -2113,7 +2108,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                goto failed;
                        }
 
-                       long index = fold_constant(array_index);
+                       long index = fold_constant_to_int(array_index);
                        if (!used_in_offsetof) {
                                if (index < 0) {
                                        errorf(&designator->source_position,
@@ -2382,10 +2377,10 @@ finish_designator:
 error_excess:
                        if (warning.other) {
                                if (env->entity != NULL) {
-                                       warningf(HERE, "excess elements in struct initializer for '%Y'",
-                                          env->entity->base.symbol);
+                                       warningf(HERE, "excess elements in initializer for '%Y'",
+                                                env->entity->base.symbol);
                                } else {
-                                       warningf(HERE, "excess elements in struct initializer");
+                                       warningf(HERE, "excess elements in initializer");
                                }
                        }
                }
@@ -2532,11 +2527,12 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                eat(T_union);
        }
 
-       symbol_t   *symbol   = NULL;
-       compound_t *compound = NULL;
+       symbol_t    *symbol   = NULL;
+       compound_t  *compound = NULL;
+       attribute_t *attributes = NULL;
 
        if (token.type == T___attribute__) {
-               parse_attributes(NULL);
+               attributes = parse_attributes(NULL);
        }
 
        entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
@@ -2578,6 +2574,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                entity_t *entity = allocate_entity_zero(kind);
                compound         = &entity->compound;
 
+               compound->alignment            = 1;
                compound->base.namespc         = NAMESPACE_TAG;
                compound->base.source_position = token.source_position;
                compound->base.symbol          = symbol;
@@ -2590,7 +2587,6 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
 
        if (token.type == '{') {
                parse_compound_type_entries(compound);
-               parse_attributes(NULL);
 
                /* ISO/IEC 14882:1998(E) §7.1.3:5 */
                if (symbol == NULL) {
@@ -2599,6 +2595,10 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                }
        }
 
+       if (attributes != NULL) {
+               handle_entity_attributes(attributes, (entity_t*) compound);
+       }
+
        return compound;
 }
 
@@ -2978,101 +2978,6 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
        return entity;
 }
 
-/**
- * Finish the construction of a struct type by calculating its size, offsets,
- * alignment.
- */
-static void finish_struct_type(compound_type_t *type)
-{
-       assert(type->compound != NULL);
-
-       compound_t *compound = type->compound;
-       if (!compound->complete)
-               return;
-
-       il_size_t      size = 0;
-       il_size_t      offset;
-       il_alignment_t alignment = compound->alignment;
-       bool           need_pad  = false;
-
-       entity_t *entry = compound->members.entities;
-       for (; entry != NULL; entry = entry->base.next) {
-               if (entry->kind != ENTITY_COMPOUND_MEMBER)
-                       continue;
-
-               type_t *m_type = entry->declaration.type;
-               if (! is_type_valid(skip_typeref(m_type))) {
-                       /* simply ignore errors here */
-                       continue;
-               }
-               il_alignment_t m_alignment = get_type_alignment(m_type);
-               if (m_alignment > alignment)
-                       alignment = m_alignment;
-
-               offset = (size + m_alignment - 1) & -m_alignment;
-
-               if (offset > size)
-                       need_pad = true;
-               entry->compound_member.offset = offset;
-               size = offset + get_type_size(m_type);
-       }
-
-       offset = (size + alignment - 1) & -alignment;
-       if (offset > size)
-               need_pad = true;
-
-       if (need_pad) {
-               if (warning.padded) {
-                       warningf(&compound->base.source_position, "'%T' needs padding",
-                                type);
-               }
-       } else if (compound->packed && warning.packed) {
-               warningf(&compound->base.source_position,
-                        "superfluous packed attribute on '%T'", type);
-       }
-
-       compound->size      = offset;
-       compound->alignment = alignment;
-}
-
-/**
- * Finish the construction of an union type by calculating
- * its size and alignment.
- */
-static void finish_union_type(compound_type_t *type)
-{
-       assert(type->compound != NULL);
-
-       compound_t *compound = type->compound;
-       if (! compound->complete)
-               return;
-
-       il_size_t      size      = 0;
-       il_alignment_t alignment = compound->alignment;
-
-       entity_t *entry = compound->members.entities;
-       for (; entry != NULL; entry = entry->base.next) {
-               if (entry->kind != ENTITY_COMPOUND_MEMBER)
-                       continue;
-
-               type_t *m_type = entry->declaration.type;
-               if (! is_type_valid(skip_typeref(m_type)))
-                       continue;
-
-               entry->compound_member.offset = 0;
-               il_size_t m_size = get_type_size(m_type);
-               if (m_size > size)
-                       size = m_size;
-               il_alignment_t m_alignment = get_type_alignment(m_type);
-               if (m_alignment > alignment)
-                       alignment = m_alignment;
-       }
-       size = (size + alignment - 1) & -alignment;
-
-       compound->size      = size;
-       compound->alignment = alignment;
-}
-
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
        type_t            *type              = NULL;
@@ -3218,13 +3123,11 @@ wrong_thread_stoarge_class:
                        type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
 
                        type->compound.compound = parse_compound_type_specifier(true);
-                       finish_struct_type(&type->compound);
                        break;
                case T_union:
                        CHECK_DOUBLE_TYPE();
                        type = allocate_type_zero(TYPE_COMPOUND_UNION);
                        type->compound.compound = parse_compound_type_specifier(false);
-                       finish_union_type(&type->compound);
                        break;
                case T_enum:
                        CHECK_DOUBLE_TYPE();
@@ -3621,8 +3524,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
            !is_typedef_symbol(token.v.symbol)) {
                token_type_t la1_type = (token_type_t)look_ahead(1)->type;
                if (la1_type == ',' || la1_type == ')') {
-                       type->kr_style_parameters    = true;
-                       type->unspecified_parameters = true;
+                       type->kr_style_parameters = true;
                        parse_identifier_list(scope);
                        goto parameters_finished;
                }
@@ -3816,21 +3718,8 @@ static construct_type_t *parse_function_declarator(scope_t *scope)
        type_t          *type  = allocate_type_zero(TYPE_FUNCTION);
        function_type_t *ftype = &type->function;
 
-       ftype->linkage = current_linkage;
-
-#if 0
-       switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) {
-               case DM_NONE:     break;
-               case DM_CDECL:    ftype->calling_convention = CC_CDECL;    break;
-               case DM_STDCALL:  ftype->calling_convention = CC_STDCALL;  break;
-               case DM_FASTCALL: ftype->calling_convention = CC_FASTCALL; break;
-               case DM_THISCALL: ftype->calling_convention = CC_THISCALL; break;
-
-               default:
-                       errorf(HERE, "multiple calling conventions in declaration");
-                       break;
-       }
-#endif
+       ftype->linkage            = current_linkage;
+       ftype->calling_convention = CC_DEFAULT;
 
        parse_parameters(ftype, scope);
 
@@ -4060,7 +3949,8 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_
 
                        if (size_expression != NULL) {
                                if (is_constant_expression(size_expression)) {
-                                       long const size                 = fold_constant(size_expression);
+                                       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
@@ -4308,7 +4198,7 @@ static type_t *parse_abstract_declarator(type_t *base_type)
  * @param decl    the declaration to check
  * @param type    the function type of the declaration
  */
-static void check_type_of_main(const entity_t *entity)
+static void check_main(const entity_t *entity)
 {
        const source_position_t *pos = &entity->base.source_position;
        if (entity->kind != ENTITY_FUNCTION) {
@@ -4417,7 +4307,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                if (warning.main && current_scope == file_scope
                                && is_sym_main(symbol)) {
-                       check_type_of_main(entity);
+                       check_main(entity);
                }
        }
 
@@ -4490,6 +4380,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
                                                &previous_entity->base.source_position);
                        } else {
                                unsigned old_storage_class = prev_decl->storage_class;
+
                                if (warning.redundant_decls               &&
                                                is_definition                     &&
                                                !prev_decl->used                  &&
@@ -4870,7 +4761,6 @@ static void parse_kr_declaration_list(entity_t *entity)
        if (!type->function.kr_style_parameters)
                return;
 
-
        add_anchor_token('{');
 
        /* push function parameters */
@@ -4912,8 +4802,30 @@ decl_list_end:
        function_parameter_t  *parameters = NULL;
        function_parameter_t **anchor     = &parameters;
 
+       /* did we have an earlier prototype? */
+       entity_t *proto_type = get_entity(entity->base.symbol, NAMESPACE_NORMAL);
+       if (proto_type != NULL && proto_type->kind != ENTITY_FUNCTION)
+               proto_type = NULL;
+
+       function_parameter_t *proto_parameter = NULL;
+       if (proto_type != NULL) {
+               type_t *proto_type_type = proto_type->declaration.type;
+               proto_parameter         = proto_type_type->function.parameters;
+               /* If a K&R function definition has a variadic prototype earlier, then
+                * make the function definition variadic, too. This should conform to
+                * §6.7.5.3:15 and §6.9.1:8. */
+               new_type->function.variadic = proto_type_type->function.variadic;
+       } else {
+               /* §6.9.1.7: A K&R style parameter list does NOT act as a function
+                * prototype */
+               new_type->function.unspecified_parameters = true;
+       }
+
+       bool need_incompatible_warning = false;
        parameter = entity->function.parameters.entities;
-       for (; parameter != NULL; parameter = parameter->base.next) {
+       for (; parameter != NULL; parameter = parameter->base.next,
+                       proto_parameter =
+                               proto_parameter == NULL ? NULL : proto_parameter->next) {
                if (parameter->kind != ENTITY_PARAMETER)
                        continue;
 
@@ -4935,25 +4847,42 @@ decl_list_end:
 
                semantic_parameter_incomplete(parameter);
 
-               /*
-                * we need the default promoted types for the function type
-                */
-               parameter_type = get_default_promoted_type(parameter_type);
-
-               function_parameter_t *const parameter =
-                       allocate_parameter(parameter_type);
+               /* we need the default promoted types for the function type */
+               type_t *not_promoted = parameter_type;
+               parameter_type       = get_default_promoted_type(parameter_type);
+
+               /* gcc special: if the type of the prototype matches the unpromoted
+                * type don't promote */
+               if (!strict_mode && proto_parameter != NULL) {
+                       type_t *proto_p_type = skip_typeref(proto_parameter->type);
+                       type_t *promo_skip   = skip_typeref(parameter_type);
+                       type_t *param_skip   = skip_typeref(not_promoted);
+                       if (!types_compatible(proto_p_type, promo_skip)
+                               && types_compatible(proto_p_type, param_skip)) {
+                               /* don't promote */
+                               need_incompatible_warning = true;
+                               parameter_type = not_promoted;
+                       }
+               }
+               function_parameter_t *const parameter
+                       = allocate_parameter(parameter_type);
 
                *anchor = parameter;
                anchor  = &parameter->next;
        }
 
-       /* §6.9.1.7: A K&R style parameter list does NOT act as a function
-        * prototype */
-       new_type->function.parameters             = parameters;
-       new_type->function.unspecified_parameters = true;
-
+       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);
+       }
+
        entity->declaration.type = new_type;
 
        rem_anchor_token('{');
@@ -5082,7 +5011,7 @@ static int determine_truth(expression_t const* const cond)
 {
        return
                !is_constant_expression(cond) ? 0 :
-               fold_constant(cond) != 0      ? 1 :
+               fold_constant_to_bool(cond)   ? 1 :
                -1;
 }
 
@@ -5295,7 +5224,7 @@ static void check_reachable(statement_t *const stmt)
                                return;
 
                        if (is_constant_expression(expr)) {
-                               long                    const val      = fold_constant(expr);
+                               long                    const val      = fold_constant_to_int(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
                                        if (i->expression == NULL) {
@@ -5775,8 +5704,7 @@ static void parse_external_declaration(void)
        /* §6.7.5.3:14 a function definition with () means no
         * parameters (and not unspecified parameters) */
        if (type->function.unspecified_parameters &&
-                       type->function.parameters == NULL     &&
-                       !type->function.kr_style_parameters) {
+                       type->function.parameters == NULL) {
                type_t *copy                          = duplicate_type(type);
                copy->function.unspecified_parameters = false;
                type                                  = identify_new_type(copy);
@@ -5882,14 +5810,18 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
        }
 
        if (is_constant_expression(size)) {
-               long v = fold_constant(size);
+               long v = fold_constant_to_int(size);
+               const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
 
                if (v < 0) {
-                       errorf(source_position, "negative width in bit-field '%Y'", symbol);
-               } else if (v == 0) {
-                       errorf(source_position, "zero width for bit-field '%Y'", symbol);
+                       errorf(source_position, "negative width in bit-field '%Y'",
+                              user_symbol);
+               } else if (v == 0 && symbol != NULL) {
+                       errorf(source_position, "zero width for bit-field '%Y'",
+                              user_symbol);
                } else if (bit_size > 0 && (il_size_t)v > bit_size) {
-                       errorf(source_position, "width of '%Y' exceeds its type", symbol);
+                       errorf(source_position, "width of '%Y' exceeds its type",
+                              user_symbol);
                } else {
                        type->bitfield.bit_size = v;
                }
@@ -5908,12 +5840,12 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
                if (iter->base.symbol == symbol) {
                        return iter;
                } else if (iter->base.symbol == NULL) {
+                       /* search in anonymous structs and unions */
                        type_t *type = skip_typeref(iter->declaration.type);
                        if (is_type_compound(type)) {
-                               entity_t *result
-                                       = find_compound_entry(type->compound.compound, symbol);
-                               if (result != NULL)
-                                       return result;
+                               if (find_compound_entry(type->compound.compound, symbol)
+                                               != NULL)
+                                       return iter;
                        }
                        continue;
                }
@@ -5922,6 +5854,98 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
        return NULL;
 }
 
+static void check_deprecated(const source_position_t *source_position,
+                             const entity_t *entity)
+{
+       if (!warning.deprecated_declarations)
+               return;
+       if (!is_declaration(entity))
+               return;
+       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);
+       } else {
+               warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix,
+                                entity->base.symbol, &entity->base.source_position);
+       }
+}
+
+
+static expression_t *create_select(const source_position_t *pos,
+                                   expression_t *addr,
+                                   type_qualifiers_t qualifiers,
+                                                                  entity_t *entry)
+{
+       assert(entry->kind == ENTITY_COMPOUND_MEMBER);
+
+       check_deprecated(pos, entry);
+
+       expression_t *select          = allocate_expression_zero(EXPR_SELECT);
+       select->select.compound       = addr;
+       select->select.compound_entry = entry;
+
+       type_t *entry_type = entry->declaration.type;
+       type_t *res_type   = get_qualified_type(entry_type, qualifiers);
+
+       /* we always do the auto-type conversions; the & and sizeof parser contains
+        * code to revert this! */
+       select->base.type = automatic_type_conversion(res_type);
+       if (res_type->kind == TYPE_BITFIELD) {
+               select->base.type = res_type->bitfield.base_type;
+       }
+
+       return select;
+}
+
+/**
+ * Find entry with symbol in compound. Search anonymous structs and unions and
+ * creates implicit select expressions for them.
+ * Returns the adress for the innermost compound.
+ */
+static expression_t *find_create_select(const source_position_t *pos,
+                                        expression_t *addr,
+                                        type_qualifiers_t qualifiers,
+                                        compound_t *compound, symbol_t *symbol)
+{
+       entity_t *iter = compound->members.entities;
+       for (; iter != NULL; iter = iter->base.next) {
+               if (iter->kind != ENTITY_COMPOUND_MEMBER)
+                       continue;
+
+               symbol_t *iter_symbol = iter->base.symbol;
+               if (iter_symbol == NULL) {
+                       type_t *type = iter->declaration.type;
+                       if (type->kind != TYPE_COMPOUND_STRUCT
+                                       && type->kind != TYPE_COMPOUND_UNION)
+                               continue;
+
+                       compound_t *sub_compound = type->compound.compound;
+
+                       if (find_compound_entry(sub_compound, symbol) == NULL)
+                               continue;
+
+                       expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
+                       sub_addr->base.source_position = *pos;
+                       sub_addr->select.implicit      = true;
+                       return find_create_select(pos, sub_addr, qualifiers, sub_compound,
+                                                 symbol);
+               }
+
+               if (iter_symbol == symbol) {
+                       return create_select(pos, addr, qualifiers, iter);
+               }
+       }
+
+       return NULL;
+}
+
 static void parse_compound_declarators(compound_t *compound,
                const declaration_specifiers_t *specifiers)
 {
@@ -5936,7 +5960,17 @@ static void parse_compound_declarators(compound_t *compound,
                        expression_t *size = parse_constant_expression();
 
                        type_t *type = make_bitfield_type(base_type, size,
-                                       &source_position, sym_anonymous);
+                                       &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;
+                       }
 
                        entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
                        entity->base.namespc                       = NAMESPACE_NORMAL;
@@ -5944,6 +5978,11 @@ static void parse_compound_declarators(compound_t *compound,
                        entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
                        entity->declaration.storage_class          = STORAGE_CLASS_NONE;
                        entity->declaration.type                   = type;
+                       entity->declaration.attributes             = attributes;
+
+                       if (attributes != NULL) {
+                               handle_entity_attributes(attributes, entity);
+                       }
                        append_entity(&compound->members, entity);
                } else {
                        entity = parse_declarator(specifiers,
@@ -5973,7 +6012,10 @@ static void parse_compound_declarators(compound_t *compound,
                                        type_t *type          = entity->declaration.type;
                                        type_t *bitfield_type = make_bitfield_type(type, size,
                                                        &source_position, entity->base.symbol);
+
+                                       attribute_t *attributes = parse_attributes(NULL);
                                        entity->declaration.type = bitfield_type;
+                                       handle_entity_attributes(attributes, entity);
                                } else {
                                        type_t *orig_type = entity->declaration.type;
                                        type_t *type      = skip_typeref(orig_type);
@@ -6228,10 +6270,12 @@ static entity_t *create_implicit_function(symbol_t *symbol,
        entity->base.symbol                        = symbol;
        entity->base.source_position               = *source_position;
 
-       bool strict_prototypes_old = warning.strict_prototypes;
-       warning.strict_prototypes  = false;
-       record_entity(entity, false);
-       warning.strict_prototypes = strict_prototypes_old;
+       if (current_scope != NULL) {
+               bool strict_prototypes_old = warning.strict_prototypes;
+               warning.strict_prototypes  = false;
+               record_entity(entity, false);
+               warning.strict_prototypes = strict_prototypes_old;
+       }
 
        return entity;
 }
@@ -6272,11 +6316,23 @@ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
        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)
 {
-       type_t *res = make_function_1_type(return_type, argument_type);
-       res->function.variadic = 1;
-       return res;
+       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);
 }
 
 /**
@@ -6453,24 +6509,7 @@ static expression_t *parse_reference(void)
                current_function->need_closure = true;
        }
 
-       /* check for deprecated functions */
-       if (warning.deprecated_declarations
-               && is_declaration(entity)
-               && entity->declaration.modifiers & DM_DEPRECATED) {
-
-               char const *const prefix = entity->kind == ENTITY_FUNCTION ?
-                       "function" : "variable";
-               const char *deprecated_string
-                       = get_deprecated_string(entity->declaration.attributes);
-               if (deprecated_string != NULL) {
-                       warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"",
-                                prefix, entity->base.symbol, &entity->base.source_position,
-                                deprecated_string);
-               } else {
-                       warningf(HERE, "%s '%Y' is deprecated (declared %P)", prefix,
-                                entity->base.symbol, &entity->base.source_position);
-               }
-       }
+       check_deprecated(HERE, entity);
 
        if (warning.init_self && entity == current_init_decl && !in_type_prop
            && entity->kind == ENTITY_VARIABLE) {
@@ -6996,31 +7035,6 @@ end_error:
        return create_invalid_expression();
 }
 
-#if 0
-/**
- * Parses a __builtin_expect(, end_error) expression.
- */
-static expression_t *parse_builtin_expect(void, end_error)
-{
-       expression_t *expression
-               = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT);
-
-       eat(T___builtin_expect);
-
-       expect('(', end_error);
-       expression->binary.left = parse_assignment_expression();
-       expect(',', end_error);
-       expression->binary.right = parse_constant_expression();
-       expect(')', end_error);
-
-       expression->base.type = expression->binary.left->base.type;
-
-       return expression;
-end_error:
-       return create_invalid_expression();
-}
-#endif
-
 /**
  * Parses a MS assume() expression.
  */
@@ -7331,29 +7345,26 @@ static expression_t *parse_alignof(void)
        return parse_typeprop(EXPR_ALIGNOF);
 }
 
-static expression_t *parse_select_expression(expression_t *compound)
+static expression_t *parse_select_expression(expression_t *addr)
 {
-       expression_t *select    = allocate_expression_zero(EXPR_SELECT);
-       select->select.compound = compound;
-
        assert(token.type == '.' || token.type == T_MINUSGREATER);
-       bool is_pointer = (token.type == T_MINUSGREATER);
+       bool select_left_arrow = (token.type == T_MINUSGREATER);
        next_token();
 
        if (token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
-               return select;
+               return create_invalid_expression();
        }
        symbol_t *symbol = token.v.symbol;
        next_token();
 
-       type_t *const orig_type = compound->base.type;
+       type_t *const orig_type = addr->base.type;
        type_t *const type      = skip_typeref(orig_type);
 
        type_t *type_left;
        bool    saw_error = false;
        if (is_type_pointer(type)) {
-               if (!is_pointer) {
+               if (!select_left_arrow) {
                        errorf(HERE,
                               "request for member '%Y' in something not a struct or union, but '%T'",
                               symbol, orig_type);
@@ -7361,56 +7372,41 @@ static expression_t *parse_select_expression(expression_t *compound)
                }
                type_left = skip_typeref(type->pointer.points_to);
        } else {
-               if (is_pointer && is_type_valid(type)) {
+               if (select_left_arrow && is_type_valid(type)) {
                        errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
                        saw_error = true;
                }
                type_left = type;
        }
 
-       entity_t *entry;
-       if (type_left->kind == TYPE_COMPOUND_STRUCT ||
-           type_left->kind == TYPE_COMPOUND_UNION) {
-               compound_t *compound = type_left->compound.compound;
-
-               if (!compound->complete) {
-                       errorf(HERE, "request for member '%Y' of incomplete type '%T'",
-                              symbol, type_left);
-                       goto create_error_entry;
-               }
+       if (type_left->kind != TYPE_COMPOUND_STRUCT &&
+           type_left->kind != TYPE_COMPOUND_UNION) {
 
-               entry = find_compound_entry(compound, symbol);
-               if (entry == NULL) {
-                       errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
-                       goto create_error_entry;
-               }
-       } else {
                if (is_type_valid(type_left) && !saw_error) {
                        errorf(HERE,
                               "request for member '%Y' in something not a struct or union, but '%T'",
                               symbol, type_left);
                }
-create_error_entry:
-               entry = create_error_entity(symbol, ENTITY_COMPOUND_MEMBER);
+               return create_invalid_expression();
        }
 
-       assert(is_declaration(entry));
-       select->select.compound_entry = entry;
-
-       type_t *entry_type = entry->declaration.type;
-       type_t *res_type
-               = get_qualified_type(entry_type, type_left->base.qualifiers);
+       compound_t *compound = type_left->compound.compound;
+       if (!compound->complete) {
+               errorf(HERE, "request for member '%Y' in incomplete type '%T'",
+                      symbol, type_left);
+               return create_invalid_expression();
+       }
 
-       /* we always do the auto-type conversions; the & and sizeof parser contains
-        * code to revert this! */
-       select->base.type = automatic_type_conversion(res_type);
+       type_qualifiers_t  qualifiers = type_left->base.qualifiers;
+       expression_t      *result
+               = find_create_select(HERE, addr, qualifiers, compound, symbol);
 
-       type_t *skipped = skip_typeref(res_type);
-       if (skipped->kind == TYPE_BITFIELD) {
-               select->base.type = skipped->bitfield.base_type;
+       if (result == NULL) {
+               errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+               return create_invalid_expression();
        }
 
-       return select;
+       return result;
 }
 
 static void check_call_argument(type_t          *expected_type,
@@ -8294,7 +8290,7 @@ static void warn_div_by_zero(binary_expression_t const *const expression)
        /* The type of the right operand can be different for /= */
        if (is_type_integer(right->base.type) &&
            is_constant_expression(right)     &&
-           fold_constant(right) == 0) {
+           !fold_constant_to_bool(right)) {
                warningf(&expression->base.source_position, "division by zero");
        }
 }
@@ -8345,7 +8341,7 @@ static bool semantic_shift(binary_expression_t *expression)
        type_left = promote_integer(type_left);
 
        if (is_constant_expression(right)) {
-               long count = fold_constant(right);
+               long count = fold_constant_to_int(right);
                if (count < 0) {
                        warningf(&right->base.source_position,
                                        "shift count must be non-negative");
@@ -8494,7 +8490,7 @@ static bool maybe_negative(expression_t const *const expr)
 {
        return
                !is_constant_expression(expr) ||
-               fold_constant(expr) < 0;
+               fold_constant_to_int(expr) < 0;
 }
 
 /**
@@ -9352,7 +9348,7 @@ static statement_t *parse_case_statement(void)
                }
                statement->case_label.is_bad = true;
        } else {
-               long const val = fold_constant(expression);
+               long const val = fold_constant_to_int(expression);
                statement->case_label.first_case = val;
                statement->case_label.last_case  = val;
        }
@@ -9371,7 +9367,7 @@ static statement_t *parse_case_statement(void)
                                }
                                statement->case_label.is_bad = true;
                        } else {
-                               long const val = fold_constant(end_range);
+                               long const val = fold_constant_to_int(end_range);
                                statement->case_label.last_case = val;
 
                                if (warning.other && val < statement->case_label.first_case) {
@@ -9599,7 +9595,7 @@ static void check_enum_cases(const switch_statement_t *statement)
        for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
             entry = entry->base.next) {
                const expression_t *expression = entry->enum_value.value;
-               long                value      = expression != NULL ? fold_constant(expression) : last_value + 1;
+               long                value      = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
                bool                found      = false;
                for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
                        if (l->expression == NULL)
@@ -9765,6 +9761,12 @@ static statement_t *parse_for(void)
        size_t const  top       = environment_top();
        scope_t      *old_scope = scope_push(&statement->fors.scope);
 
+       bool old_gcc_extension = in_gcc_extension;
+       while (token.type == T___extension__) {
+               next_token();
+               in_gcc_extension = true;
+       }
+
        if (token.type == ';') {
                next_token();
        } else if (is_declaration_specifier(&token, false)) {
@@ -9781,6 +9783,7 @@ static statement_t *parse_for(void)
                rem_anchor_token(';');
                expect(';', end_error2);
        }
+       in_gcc_extension = old_gcc_extension;
 
        if (token.type != ';') {
                add_anchor_token(';');
@@ -10897,6 +10900,36 @@ static void complete_incomplete_arrays(void)
        }
 }
 
+void prepare_main_collect2(entity_t *entity)
+{
+       // create call to __main
+       symbol_t *symbol         = symbol_table_insert("__main");
+       entity_t *subsubmain_ent
+               = create_implicit_function(symbol, &builtin_source_position);
+
+       expression_t *ref         = allocate_expression_zero(EXPR_REFERENCE);
+       type_t       *ftype       = subsubmain_ent->declaration.type;
+       ref->base.source_position = builtin_source_position;
+       ref->base.type            = make_pointer_type(ftype, TYPE_QUALIFIER_NONE);
+       ref->reference.entity     = subsubmain_ent;
+
+       expression_t *call = allocate_expression_zero(EXPR_CALL);
+       call->base.source_position = builtin_source_position;
+       call->base.type            = type_void;
+       call->call.function        = ref;
+
+       statement_t *expr_statement = allocate_statement_zero(STATEMENT_EXPRESSION);
+       expr_statement->base.source_position  = builtin_source_position;
+       expr_statement->expression.expression = call;
+
+       statement_t *statement = entity->function.statement;
+       assert(statement->kind == STATEMENT_COMPOUND);
+       compound_statement_t *compounds = &statement->compound;
+
+       expr_statement->base.next = compounds->statements;
+       compounds->statements     = expr_statement;
+}
+
 void parse(void)
 {
        lookahead_bufpos = 0;