From eeccf731219c13e437ba0eeb5f06363977e67ea3 Mon Sep 17 00:00:00 2001 From: Christoph Mallon Date: Thu, 20 Dec 2012 14:11:26 +0100 Subject: [PATCH] semantic: Extend expression classification to detect integer constant expressions. This is required for strict detection of null pointer constants and VLAs. --- ast.c | 72 ++++++++++++++++++++++++++++++++++-------------------- ast.h | 3 ++- ast2firm.c | 23 ++++++++--------- parser.c | 40 ++++++++++++++++-------------- 4 files changed, 81 insertions(+), 57 deletions(-) diff --git a/ast.c b/ast.c index f852a9d..fe99462 100644 --- a/ast.c +++ b/ast.c @@ -1630,7 +1630,7 @@ expression_classification_t is_linker_constant(const expression_t *expression) case EXPR_CONDITIONAL: { expression_t *const c = expression->conditional.condition; expression_classification_t const cclass = is_constant_expression(c); - if (cclass != EXPR_CLASS_CONSTANT) + if (cclass < EXPR_CLASS_CONSTANT) return cclass; if (fold_constant_to_bool(c)) { @@ -1720,7 +1720,7 @@ static expression_classification_t is_object_with_constant_address(const express array_access_expression_t const* const array_access = &expression->array_access; expression_classification_t const idx_class = is_constant_expression(array_access->index); - if (idx_class != EXPR_CLASS_CONSTANT) + if (idx_class < EXPR_CLASS_CONSTANT) return idx_class; expression_classification_t const ref_addr = is_object_with_constant_address(array_access->array_ref); expression_classification_t const ref_ptr = is_constant_pointer(array_access->array_ref); @@ -1746,7 +1746,7 @@ expression_classification_t is_constant_expression(const expression_t *expressio case EXPR_ENUM_CONSTANT: case EXPR_LITERAL_BOOLEAN: case EXPR_LITERAL_MS_NOOP: - return EXPR_CLASS_CONSTANT; + return EXPR_CLASS_INTEGER_CONSTANT; { type_t *type; @@ -1759,7 +1759,6 @@ expression_classification_t is_constant_expression(const expression_t *expressio goto check_type; case EXPR_LITERAL_INTEGER: - case EXPR_LITERAL_FLOATINGPOINT: type = skip_typeref(expression->base.type); goto check_type; @@ -1774,12 +1773,17 @@ expression_classification_t is_constant_expression(const expression_t *expressio goto check_type; check_type: + return is_type_valid(type) ? EXPR_CLASS_INTEGER_CONSTANT : EXPR_CLASS_ERROR; + } + + case EXPR_LITERAL_FLOATINGPOINT: { + type_t *const type = skip_typeref(expression->base.type); return is_type_valid(type) ? EXPR_CLASS_CONSTANT : EXPR_CLASS_ERROR; } case EXPR_BUILTIN_CONSTANT_P: { expression_classification_t const c = is_constant_expression(expression->builtin_constant.value); - return c != EXPR_CLASS_ERROR ? EXPR_CLASS_CONSTANT : EXPR_CLASS_ERROR; + return c != EXPR_CLASS_ERROR ? EXPR_CLASS_INTEGER_CONSTANT : EXPR_CLASS_ERROR; } case EXPR_STRING_LITERAL: @@ -1841,6 +1845,14 @@ check_type: case EXPR_UNARY_CAST: { type_t *const type = skip_typeref(expression->base.type); + if (is_type_integer(type)) { + expression_t *const val = expression->unary.value; + if (is_type_arithmetic(skip_typeref(val->base.type))) { + return val->kind == EXPR_LITERAL_FLOATINGPOINT + ? EXPR_CLASS_INTEGER_CONSTANT + : is_constant_expression(val); + } + } if (is_type_scalar(type)) return is_constant_expression(expression->unary.value); if (!is_type_valid(type)) @@ -1876,40 +1888,48 @@ check_type: } case EXPR_BINARY_LOGICAL_AND: { - expression_t const *const left = expression->binary.left; - expression_classification_t const lclass = is_constant_expression(left); - if (lclass != EXPR_CLASS_CONSTANT) - return lclass; + expression_t const *const left = expression->binary.left; + expression_classification_t const lcls = is_constant_expression(left); + if (lcls < EXPR_CLASS_CONSTANT) + return lcls; + expression_classification_t const rcls = is_constant_expression(expression->binary.right); + if (lcls == EXPR_CLASS_INTEGER_CONSTANT && rcls == EXPR_CLASS_INTEGER_CONSTANT) + return EXPR_CLASS_INTEGER_CONSTANT; if (!fold_constant_to_bool(left)) return EXPR_CLASS_CONSTANT; - return is_constant_expression(expression->binary.right); + return rcls < EXPR_CLASS_CONSTANT ? rcls : EXPR_CLASS_CONSTANT; } case EXPR_BINARY_LOGICAL_OR: { - expression_t const *const left = expression->binary.left; - expression_classification_t const lclass = is_constant_expression(left); - if (lclass != EXPR_CLASS_CONSTANT) - return lclass; + expression_t const *const left = expression->binary.left; + expression_classification_t const lcls = is_constant_expression(left); + if (lcls < EXPR_CLASS_CONSTANT) + return lcls; + expression_classification_t const rcls = is_constant_expression(expression->binary.right); + if (lcls == EXPR_CLASS_INTEGER_CONSTANT && rcls == EXPR_CLASS_INTEGER_CONSTANT) + return EXPR_CLASS_INTEGER_CONSTANT; if (fold_constant_to_bool(left)) return EXPR_CLASS_CONSTANT; - return is_constant_expression(expression->binary.right); + return rcls < EXPR_CLASS_CONSTANT ? rcls : EXPR_CLASS_CONSTANT; } case EXPR_COMPOUND_LITERAL: return is_constant_initializer(expression->compound_literal.initializer); case EXPR_CONDITIONAL: { - expression_t *const condition = expression->conditional.condition; - expression_classification_t const cclass = is_constant_expression(condition); - if (cclass != EXPR_CLASS_CONSTANT) - return cclass; - - if (fold_constant_to_bool(condition)) { - expression_t const *const t = expression->conditional.true_expression; - return t == NULL ? EXPR_CLASS_CONSTANT : is_constant_expression(t); - } else { - return is_constant_expression(expression->conditional.false_expression); - } + expression_t *const cond = expression->conditional.condition; + expression_classification_t const ccls = is_constant_expression(cond); + if (ccls < EXPR_CLASS_CONSTANT) + return ccls; + expression_t const *const t = expression->conditional.true_expression; + expression_classification_t const tcls = t == NULL ? ccls : is_constant_expression(t); + expression_classification_t const fcls = is_constant_expression(expression->conditional.false_expression); + if (ccls == EXPR_CLASS_INTEGER_CONSTANT && + tcls == EXPR_CLASS_INTEGER_CONSTANT && + fcls == EXPR_CLASS_INTEGER_CONSTANT) + return EXPR_CLASS_INTEGER_CONSTANT; + expression_classification_t const cls = fold_constant_to_bool(cond) ? tcls : fcls; + return cls < EXPR_CLASS_CONSTANT ? cls : EXPR_CLASS_CONSTANT; } case EXPR_ERROR: diff --git a/ast.h b/ast.h index f27f876..3a474e7 100644 --- a/ast.h +++ b/ast.h @@ -85,7 +85,8 @@ void change_indent(int delta); typedef enum expression_classification_t { EXPR_CLASS_VARIABLE, EXPR_CLASS_ERROR, - EXPR_CLASS_CONSTANT + EXPR_CLASS_CONSTANT, + EXPR_CLASS_INTEGER_CONSTANT } expression_classification_t; /** diff --git a/ast2firm.c b/ast2firm.c index c0018ba..9ddd3b2 100644 --- a/ast2firm.c +++ b/ast2firm.c @@ -2158,10 +2158,10 @@ static ir_node *handle_assume_compare(dbg_info *dbi, } expression_t *con = NULL; - if (is_local_variable(op1) && is_constant_expression(op2) == EXPR_CLASS_CONSTANT) { + if (is_local_variable(op1) && is_constant_expression(op2) != EXPR_CLASS_VARIABLE) { var = op1->reference.entity; con = op2; - } else if (is_constant_expression(op1) == EXPR_CLASS_CONSTANT && is_local_variable(op2)) { + } else if (is_constant_expression(op1) != EXPR_CLASS_VARIABLE && is_local_variable(op2)) { relation = get_inversed_relation(relation); var = op2->reference.entity; con = op1; @@ -2444,7 +2444,7 @@ static void compare_to_control_flow(expression_t const *const expr, ir_node *con /* set branch prediction info based on __builtin_expect */ if (is_builtin_expect(expr) && is_Cond(cond)) { call_argument_t *const argument = expr->call.arguments->next; - if (is_constant_expression(argument->expression) == EXPR_CLASS_CONSTANT) { + if (is_constant_expression(argument->expression) != EXPR_CLASS_VARIABLE) { bool const cnst = fold_constant_to_bool(argument->expression); cond_jmp_predicate const pred = cnst ? COND_JMP_PRED_TRUE : COND_JMP_PRED_FALSE; set_Cond_jmp_pred(cond, pred); @@ -2644,9 +2644,10 @@ static ir_node *compound_literal_addr(compound_literal_expression_t const *const type_t *type = expression->type; initializer_t *initializer = expression->initializer; - if (expression->global_scope || - ((type->base.qualifiers & TYPE_QUALIFIER_CONST) - && is_constant_initializer(initializer) == EXPR_CLASS_CONSTANT)) { + if (expression->global_scope || ( + type->base.qualifiers & TYPE_QUALIFIER_CONST && + is_constant_initializer(initializer) != EXPR_CLASS_VARIABLE + )) { ir_entity *entity = create_initializer_entity(dbgi, initializer, type); return create_symconst(dbgi, entity); } else { @@ -2745,7 +2746,7 @@ static void init_ir_types(void); ir_tarval *fold_constant_to_tarval(const expression_t *expression) { - assert(is_constant_expression(expression) == EXPR_CLASS_CONSTANT); + assert(is_constant_expression(expression) >= EXPR_CLASS_CONSTANT); bool constant_folding_old = constant_folding; constant_folding = true; @@ -2771,7 +2772,7 @@ ir_tarval *fold_constant_to_tarval(const expression_t *expression) static complex_constant fold_complex_constant(const expression_t *expression) { - assert(is_constant_expression(expression) == EXPR_CLASS_CONSTANT); + assert(is_constant_expression(expression) >= EXPR_CLASS_CONSTANT); bool constant_folding_old = constant_folding; constant_folding = true; @@ -3145,7 +3146,7 @@ static ir_node *builtin_constant_to_firm( const builtin_constant_expression_t *expression) { ir_mode *const mode = get_ir_mode_storage(expression->base.type); - bool const v = is_constant_expression(expression->value) == EXPR_CLASS_CONSTANT; + bool const v = is_constant_expression(expression->value) != EXPR_CLASS_VARIABLE; return create_Const_from_bool(mode, v); } @@ -5152,7 +5153,7 @@ static ir_node *do_while_statement_to_firm(do_while_statement_t *statement) expression_t *const cond = statement->condition; /* Avoid an explicit body block in case of do ... while (0);. */ - if (is_constant_expression(cond) == EXPR_CLASS_CONSTANT && !fold_constant_to_bool(cond)) { + if (is_constant_expression(cond) != EXPR_CLASS_VARIABLE && !fold_constant_to_bool(cond)) { /* do ... while (0);. */ statement_to_firm(statement->body); jump_to_target(&continue_target); @@ -5208,7 +5209,7 @@ static ir_node *for_statement_to_firm(for_statement_t *statement) /* Create the condition. */ expression_t *const cond = statement->condition; - if (cond && (is_constant_expression(cond) != EXPR_CLASS_CONSTANT || !fold_constant_to_bool(cond))) { + if (cond && (is_constant_expression(cond) == EXPR_CLASS_VARIABLE || !fold_constant_to_bool(cond))) { jump_target body_target; init_jump_target(&body_target, NULL); expression_to_control_flow(cond, &body_target, &break_target); diff --git a/parser.c b/parser.c index 74374c5..d49ec8d 100644 --- a/parser.c +++ b/parser.c @@ -860,14 +860,13 @@ static bool is_null_pointer_constant(const expression_t *expression) 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; @@ -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) { @@ -5463,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 { @@ -7871,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"); @@ -7931,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) { @@ -8057,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) @@ -8944,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"); } @@ -8968,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"); } -- 2.20.1