condeval is called jump threading now
[cparser] / parser.c
index 07886f4..1686f34 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -114,7 +114,7 @@ static declaration_t      **incomplete_arrays;
 #define POP_PARENT ((void)(current_parent = prev_parent))
 
 /** special symbol used for anonymous entities. */
-static const symbol_t *sym_anonymous = NULL;
+static symbol_t *sym_anonymous = NULL;
 
 /** The token anchor set */
 static unsigned char token_anchor_set[T_LAST_TOKEN];
@@ -796,7 +796,7 @@ static entity_t *get_entity(const symbol_t *const symbol,
 /* §6.2.3:1 24)  There is only one name space for tags even though three are
  * possible. */
 static entity_t *get_tag(symbol_t const *const symbol,
-               entity_kind_tag_t const kind)
+                         entity_kind_tag_t const kind)
 {
        entity_t *entity = get_entity(symbol, NAMESPACE_TAG);
        if (entity != NULL && entity->kind != kind) {
@@ -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;
@@ -1882,7 +1877,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
        mark_vars_read(expression, NULL);
        if (must_be_constant && !is_initializer_constant(expression)) {
                errorf(&expression->base.source_position,
-                      "Initialisation expression '%E' is not constant",
+                      "initialisation expression '%E' is not constant",
                       expression);
        }
 
@@ -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");
                                }
                        }
                }
@@ -4163,7 +4158,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                storage_class_t storage_class = specifiers->storage_class;
                entity->declaration.declared_storage_class = storage_class;
 
-               if (storage_class == STORAGE_CLASS_NONE && current_scope != file_scope)
+               if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
                        storage_class = STORAGE_CLASS_AUTO;
                entity->declaration.storage_class = storage_class;
        }
@@ -4766,10 +4761,6 @@ static void parse_kr_declaration_list(entity_t *entity)
        if (!type->function.kr_style_parameters)
                return;
 
-       entity_t *proto_type = get_entity(entity->base.symbol, NAMESPACE_NORMAL);
-       if (proto_type != NULL && proto_type->kind != ENTITY_FUNCTION)
-               proto_type = NULL;
-
        add_anchor_token('{');
 
        /* push function parameters */
@@ -4811,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;
 
@@ -4834,31 +4847,42 @@ decl_list_end:
 
                semantic_parameter_incomplete(parameter);
 
-               /*
-                * we need the default promoted types for the function type
-                */
-               if (proto_type == NULL)
-                       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;
        }
 
        new_type->function.parameters = parameters;
-       if (proto_type != NULL) {
-               /* compatibility with the prototype will be checked later ... */
-               new_type->function.prototyped = true;
-       } else {
-               /* §6.9.1.7: A K&R style parameter list does NOT act as a function
-                * prototype */
-               new_type->function.unspecified_parameters = true;
-       }
-
        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('{');
@@ -5680,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);
@@ -6425,14 +6448,73 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
        }
 }
 
-static expression_t *parse_reference(void)
+/**
+ * Find an entity matching a symbol in a scope.
+ * Uses current scope if scope is NULL
+ */
+static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol,
+                               namespace_tag_t namespc)
 {
-       symbol_t *const symbol = token.v.symbol;
+       if (scope == NULL) {
+               return get_entity(symbol, namespc);
+       }
 
-       entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
+       /* we should optimize here, if scope grows above a certain size we should
+          construct a hashmap here... */
+       entity_t *entity = scope->entities;
+       for ( ; entity != NULL; entity = entity->base.next) {
+               if (entity->base.symbol == symbol && entity->base.namespc == namespc)
+                       break;
+       }
+
+       return entity;
+}
+
+static entity_t *parse_qualified_identifier(void)
+{
+       /* namespace containing the symbol */
+       symbol_t      *symbol;
+       const scope_t *lookup_scope = NULL;
+
+       if (token.type == T_COLONCOLON) {
+               next_token();
+               lookup_scope = &unit->scope;
+       }
+
+       entity_t *entity;
+       while (true) {
+               if (token.type != T_IDENTIFIER) {
+                       parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
+                       return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
+               }
+               symbol = token.v.symbol;
+               next_token();
+
+               /* lookup entity */
+               entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
+
+               if (token.type != T_COLONCOLON)
+                       break;
+               next_token();
+
+               switch (entity->kind) {
+               case ENTITY_NAMESPACE:
+                       lookup_scope = &entity->namespacee.members;
+                       break;
+               case ENTITY_STRUCT:
+               case ENTITY_UNION:
+               case ENTITY_CLASS:
+                       lookup_scope = &entity->compound.members;
+                       break;
+               default:
+                       errorf(HERE, "'%Y' must be a namespace, class, struct or union (but is a %s)",
+                              symbol, get_entity_kind_name(entity->kind));
+                       goto end_error;
+               }
+       }
 
        if (entity == NULL) {
-               if (!strict_mode && look_ahead(1)->type == '(') {
+               if (!strict_mode && token.type == '(') {
                        /* an implicitly declared function */
                        if (warning.error_implicit_function_declaration) {
                                errorf(HERE, "implicit declaration of function '%Y'", symbol);
@@ -6447,8 +6529,25 @@ static expression_t *parse_reference(void)
                }
        }
 
-       type_t *orig_type;
+       return entity;
+
+end_error:
+       /* skip further qualifications */
+       while (token.type == T_IDENTIFIER) {
+               next_token();
+               if (token.type != T_COLONCOLON)
+                       break;
+               next_token();
+       }
+
+       return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
+}
+
+static expression_t *parse_reference(void)
+{
+       entity_t *entity = parse_qualified_identifier();
 
+       type_t *orig_type;
        if (is_declaration(entity)) {
                orig_type = entity->declaration.type;
        } else if (entity->kind == ENTITY_ENUM_VALUE) {
@@ -6475,8 +6574,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;
@@ -6495,7 +6595,6 @@ static expression_t *parse_reference(void)
                         entity->declaration.type, entity->base.symbol);
        }
 
-       next_token();
        return expression;
 }
 
@@ -6840,9 +6939,12 @@ static expression_t *parse_va_start(void)
        expression_t *const expr = parse_assignment_expression();
        if (expr->kind == EXPR_REFERENCE) {
                entity_t *const entity = expr->reference.entity;
-               if (entity->base.parent_scope != &current_function->parameters
-                               || entity->base.next != NULL
-                               || entity->kind != ENTITY_PARAMETER) {
+               if (!current_function->base.type->function.variadic) {
+                       errorf(&expr->base.source_position,
+                                       "'va_start' used in non-variadic function");
+               } else if (entity->base.parent_scope != &current_function->parameters ||
+                               entity->base.next != NULL ||
+                               entity->kind != ENTITY_PARAMETER) {
                        errorf(&expr->base.source_position,
                               "second argument of 'va_start' must be last parameter of the current function");
                } else {
@@ -7177,6 +7279,8 @@ static expression_t *parse_primary_expression(void)
                case T___noop:                       return parse_noop_expression();
 
                /* Gracefully handle type names while parsing expressions. */
+               case T_COLONCOLON:
+                       return parse_reference();
                case T_IDENTIFIER:
                        if (!is_typedef_symbol(token.v.symbol)) {
                                return parse_reference();