semantic: Extend expression classification to detect integer constant expressions.
[cparser] / parser.c
index f742f33..d49ec8d 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -856,18 +856,17 @@ static bool is_null_pointer_constant(const expression_t *expression)
        /* skip void* cast */
        if (expression->kind == EXPR_UNARY_CAST) {
                type_t *const type = skip_typeref(expression->base.type);
-               if (types_compatible(type, type_void_ptr))
+               if (type == type_void_ptr)
                        expression = expression->unary.value;
        }
 
-       type_t *const type = skip_typeref(expression->base.type);
-       if (!is_type_integer(type))
-               return false;
        switch (is_constant_expression(expression)) {
-               case EXPR_CLASS_ERROR:    return true;
-               case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression);
-               default:                  return false;
+               case EXPR_CLASS_VARIABLE:         return false;
+               case EXPR_CLASS_ERROR:            return true;
+               case EXPR_CLASS_CONSTANT:         return false;
+               case EXPR_CLASS_INTEGER_CONSTANT: return !fold_constant_to_bool(expression);
        }
+       panic("invalid expression classification");
 }
 
 /**
@@ -1838,7 +1837,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        }
                } else {
                        expression_t *array_index = designator->array_index;
-                       if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT)
+                       if (is_constant_expression(array_index) < EXPR_CLASS_CONSTANT)
                                return true;
 
                        if (!is_type_array(type)) {
@@ -3558,7 +3557,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                        if (size_expression != NULL) {
                                switch (is_constant_expression(size_expression)) {
-                               case EXPR_CLASS_CONSTANT: {
+                               case EXPR_CLASS_INTEGER_CONSTANT: {
                                        long const size = fold_constant_to_int(size_expression);
                                        array_type->array.size          = size;
                                        array_type->array.size_constant = true;
@@ -3574,6 +3573,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                                        break;
                                }
 
+                               case EXPR_CLASS_CONSTANT:
                                case EXPR_CLASS_VARIABLE:
                                        array_type->array.is_vla = true;
                                        break;
@@ -4145,13 +4145,13 @@ static void parser_error_multiple_definition(entity_t *entity,
        errorf(pos, "redefinition of '%N' (declared %P)", entity, &entity->base.pos);
 }
 
-static bool is_declaration_specifier(const token_t *token)
+static bool is_declaration_specifier(token_t const *const tk)
 {
-       switch (token->kind) {
+       switch (tk->kind) {
                DECLARATION_START
                        return true;
                case T_IDENTIFIER:
-                       return is_typedef_symbol(token->base.symbol);
+                       return is_typedef_symbol(tk->base.symbol);
 
                default:
                        return false;
@@ -4587,8 +4587,8 @@ static void check_declarations(void)
 static int determine_truth(expression_t const* const cond)
 {
        return
-               is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
-               fold_constant_to_bool(cond)                         ? 1 :
+               is_constant_expression(cond) < EXPR_CLASS_CONSTANT ? 0 :
+               fold_constant_to_bool(cond)                        ? 1 :
                -1;
 }
 
@@ -4796,7 +4796,7 @@ static void check_reachable(statement_t *const stmt)
                        if (!expression_returns(expr))
                                return;
 
-                       if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
+                       if (is_constant_expression(expr) >= EXPR_CLASS_CONSTANT) {
                                ir_tarval              *const val      = fold_constant_to_tarval(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
@@ -5213,42 +5213,42 @@ static void parse_external_declaration(void)
                return;
        }
 
-       assert(is_declaration(ndeclaration));
-       type_t *const orig_type = ndeclaration->declaration.type;
-       type_t *      type      = skip_typeref(orig_type);
+       {
+               assert(is_declaration(ndeclaration));
+               type_t *const orig_type = ndeclaration->declaration.type;
+               type_t *const type      = skip_typeref(orig_type);
 
-       if (!is_type_function(type)) {
-               if (is_type_valid(type)) {
-                       errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
+               if (!is_type_function(type)) {
+                       if (is_type_valid(type)) {
+                               errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
+                       }
+                       eat_block();
+                       return;
                }
-               eat_block();
-               return;
-       }
 
-       position_t const *const pos = &ndeclaration->base.pos;
-       if (is_typeref(orig_type)) {
-               /* §6.9.1:2 */
-               errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
-       }
-
-       if (is_type_compound(skip_typeref(type->function.return_type))) {
-               warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration);
-       }
-       if (type->function.unspecified_parameters) {
-               warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration);
-       } else {
-               warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
-       }
+               position_t const *const pos = &ndeclaration->base.pos;
+               if (is_typeref(orig_type)) {
+                       /* §6.9.1:2 */
+                       errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
+               }
 
-       /* §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_t *copy                          = duplicate_type(type);
-               copy->function.unspecified_parameters = false;
-               type                                  = identify_new_type(copy);
+               if (is_type_compound(skip_typeref(type->function.return_type))) {
+                       warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration);
+               }
+               if (type->function.unspecified_parameters) {
+                       warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration);
+               } else {
+                       warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
+               }
 
-               ndeclaration->declaration.type = type;
+               /* §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_t *copy                          = duplicate_type(type);
+                       copy->function.unspecified_parameters = false;
+                       ndeclaration->declaration.type = identify_new_type(copy);
+               }
        }
 
        entity_t *const entity = record_entity(ndeclaration, true);
@@ -5307,8 +5307,7 @@ static void parse_external_declaration(void)
                                walk_statements(body, check_unreachable, NULL);
                        if (noreturn_candidate &&
                            !(function->base.modifiers & DM_NORETURN)) {
-                               position_t const *const pos = &body->base.pos;
-                               warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
+                               warningf(WARN_MISSING_NORETURN, &body->base.pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
                        }
                }
 
@@ -5464,7 +5463,7 @@ static void parse_bitfield_member(entity_t *entity)
                           type);
        }
 
-       if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) {
+       if (is_constant_expression(size) < EXPR_CLASS_CONSTANT) {
                /* error already reported by parse_constant_expression */
                size_long = get_type_size(type) * 8;
        } else {
@@ -5500,11 +5499,10 @@ static void parse_compound_declarators(compound_t *compound,
        add_anchor_token(',');
        do {
                entity_t *entity;
-
                if (token.kind == ':') {
                        /* anonymous bitfield */
                        type_t *type = specifiers->type;
-                       entity_t *const entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE);
+                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE);
                        entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
                        entity->declaration.storage_class          = STORAGE_CLASS_NONE;
                        entity->declaration.type                   = type;
@@ -5520,52 +5518,50 @@ static void parse_compound_declarators(compound_t *compound,
                                handle_entity_attributes(attributes, entity);
                        }
                        entity->declaration.attributes = attributes;
-
-                       append_entity(&compound->members, entity);
                } else {
-                       entity = parse_declarator(specifiers,
-                                       DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
+                       entity = parse_declarator(specifiers, DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
                        position_t const *const pos = &entity->base.pos;
                        if (entity->kind == ENTITY_TYPEDEF) {
                                errorf(pos, "typedef not allowed as compound member");
-                       } else {
-                               assert(entity->kind == ENTITY_COMPOUND_MEMBER);
-
-                               /* make sure we don't define a symbol multiple times */
-                               symbol_t *symbol = entity->base.symbol;
-                               if (symbol != NULL) {
-                                       entity_t *prev = find_compound_entry(compound, symbol);
-                                       if (prev != NULL) {
-                                               position_t const *const ppos = &prev->base.pos;
-                                               errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
-                                       }
+                               continue;
+                       }
+
+                       assert(entity->kind == ENTITY_COMPOUND_MEMBER);
+
+                       /* make sure we don't define a symbol multiple times */
+                       symbol_t *symbol = entity->base.symbol;
+                       if (symbol != NULL) {
+                               entity_t *prev = find_compound_entry(compound, symbol);
+                               if (prev != NULL) {
+                                       position_t const *const ppos = &prev->base.pos;
+                                       errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
                                }
+                       }
 
-                               if (token.kind == ':') {
-                                       parse_bitfield_member(entity);
+                       if (token.kind == ':') {
+                               parse_bitfield_member(entity);
 
-                                       attribute_t *attributes = parse_attributes(NULL);
-                                       handle_entity_attributes(attributes, entity);
-                               } else {
-                                       type_t *orig_type = entity->declaration.type;
-                                       type_t *type      = skip_typeref(orig_type);
-                                       if (is_type_function(type)) {
-                                               errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
-                                       } else if (is_type_incomplete(type)) {
-                                               /* §6.7.2.1:16 flexible array member */
-                                               if (!is_type_array(type)       ||
-                                                               token.kind          != ';' ||
-                                                               look_ahead(1)->kind != '}') {
-                                                       errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
-                                               } else if (compound->members.entities == NULL) {
-                                                       errorf(pos, "flexible array member in otherwise empty struct");
-                                               }
+                               attribute_t *attributes = parse_attributes(NULL);
+                               handle_entity_attributes(attributes, entity);
+                       } else {
+                               type_t *orig_type = entity->declaration.type;
+                               type_t *type      = skip_typeref(orig_type);
+                               if (is_type_function(type)) {
+                                       errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
+                               } else if (is_type_incomplete(type)) {
+                                       /* §6.7.2.1:16 flexible array member */
+                                       if (!is_type_array(type)       ||
+                                                       token.kind          != ';' ||
+                                                       look_ahead(1)->kind != '}') {
+                                               errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
+                                       } else if (compound->members.entities == NULL) {
+                                               errorf(pos, "flexible array member in otherwise empty struct");
                                        }
                                }
-
-                               append_entity(&compound->members, entity);
                        }
                }
+
+               append_entity(&compound->members, entity);
        } while (accept(','));
        rem_anchor_token(',');
        rem_anchor_token(';');
@@ -7875,7 +7871,7 @@ static void warn_div_by_zero(binary_expression_t const *const expression)
        expression_t const *const right = expression->right;
        /* The type of the right operand can be different for /= */
        if (is_type_integer(skip_typeref(right->base.type))      &&
-           is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
+           is_constant_expression(right) >= EXPR_CLASS_CONSTANT &&
            !fold_constant_to_bool(right)) {
                position_t const *const pos = &expression->base.pos;
                warningf(WARN_DIV_BY_ZERO, pos, "division by zero");
@@ -7935,7 +7931,7 @@ static bool semantic_shift(binary_expression_t *expression)
 
        type_left = promote_integer(type_left);
 
-       if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
+       if (is_constant_expression(right) >= EXPR_CLASS_CONSTANT) {
                position_t const *const pos   = &right->base.pos;
                long              const count = fold_constant_to_int(right);
                if (count < 0) {
@@ -8061,10 +8057,12 @@ static void warn_string_literal_address(expression_t const* expr)
 static bool maybe_negative(expression_t const *const expr)
 {
        switch (is_constant_expression(expr)) {
-               case EXPR_CLASS_ERROR:    return false;
-               case EXPR_CLASS_CONSTANT: return constant_is_negative(expr);
-               default:                  return true;
+               case EXPR_CLASS_VARIABLE:         return true;
+               case EXPR_CLASS_ERROR:            return false;
+               case EXPR_CLASS_CONSTANT:
+               case EXPR_CLASS_INTEGER_CONSTANT: return constant_is_negative(expr);
        }
+       panic("invalid expression classification");
 }
 
 static void warn_comparison(position_t const *const pos, expression_t const *const expr, expression_t const *const other)
@@ -8948,7 +8946,7 @@ static statement_t *parse_case_statement(void)
 
        statement->case_label.expression = expression;
        expression_classification_t const expr_class = is_constant_expression(expression);
-       if (expr_class != EXPR_CLASS_CONSTANT) {
+       if (expr_class < EXPR_CLASS_CONSTANT) {
                if (expr_class != EXPR_CLASS_ERROR) {
                        errorf(pos, "case label does not reduce to an integer constant");
                }
@@ -8972,7 +8970,7 @@ static statement_t *parse_case_statement(void)
                        end_range = create_implicit_cast(end_range, type);
                        statement->case_label.end_range = end_range;
                        expression_classification_t const end_class = is_constant_expression(end_range);
-                       if (end_class != EXPR_CLASS_CONSTANT) {
+                       if (end_class < EXPR_CLASS_CONSTANT) {
                                if (end_class != EXPR_CLASS_ERROR) {
                                        errorf(pos, "case range does not reduce to an integer constant");
                                }