}
}
-bool is_constant_initializer(const initializer_t *initializer)
+expression_classification_t is_constant_initializer(const initializer_t *initializer)
{
switch (initializer->kind) {
case INITIALIZER_STRING:
case INITIALIZER_WIDE_STRING:
case INITIALIZER_DESIGNATOR:
- return true;
+ return EXPR_CLASS_CONSTANT;
case INITIALIZER_VALUE:
return is_constant_expression(initializer->value.value);
- case INITIALIZER_LIST:
+ case INITIALIZER_LIST: {
+ expression_classification_t all = EXPR_CLASS_CONSTANT;
for (size_t i = 0; i < initializer->list.len; ++i) {
initializer_t *sub_initializer = initializer->list.initializers[i];
- if (!is_constant_initializer(sub_initializer))
- return false;
+ expression_classification_t const cur = is_constant_initializer(sub_initializer);
+ if (all > cur) {
+ all = cur;
+ }
}
- return true;
+ return all;
+ }
}
panic("invalid initializer kind found");
}
-static bool is_object_with_linker_constant_address(const expression_t *expression)
+static expression_classification_t is_object_with_linker_constant_address(const expression_t *expression)
{
switch (expression->kind) {
case EXPR_UNARY_DEREFERENCE:
}
}
- case EXPR_ARRAY_ACCESS:
- return is_constant_expression(expression->array_access.index)
- && is_address_constant(expression->array_access.array_ref);
+ case EXPR_ARRAY_ACCESS: {
+ expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
+ expression_classification_t const idx = is_constant_expression(expression->array_access.index);
+ return ref < idx ? ref : idx;
+ }
case EXPR_REFERENCE: {
entity_t *entity = expression->reference.entity;
case STORAGE_CLASS_STATIC:
return
entity->kind != ENTITY_VARIABLE ||
- !entity->variable.thread_local;
+ !entity->variable.thread_local ? EXPR_CLASS_CONSTANT :
+ EXPR_CLASS_VARIABLE;
case STORAGE_CLASS_REGISTER:
case STORAGE_CLASS_TYPEDEF:
break;
}
}
- return false;
+ return EXPR_CLASS_VARIABLE;
}
+ case EXPR_INVALID:
+ return EXPR_CLASS_ERROR;
+
default:
- return false;
+ return EXPR_CLASS_VARIABLE;
}
}
-bool is_address_constant(const expression_t *expression)
+expression_classification_t is_address_constant(const expression_t *expression)
{
switch (expression->kind) {
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_FUNCNAME:
case EXPR_LABEL_ADDRESS:
- return true;
+ return EXPR_CLASS_CONSTANT;
case EXPR_UNARY_TAKE_ADDRESS:
return is_object_with_linker_constant_address(expression->unary.value);
!(get_atomic_type_flags(dest->atomic.akind) & ATOMIC_TYPE_FLAG_INTEGER) ||
get_atomic_type_size(dest->atomic.akind) < get_atomic_type_size(get_intptr_kind())
))
- return false;
+ return EXPR_CLASS_VARIABLE;
- return (is_constant_expression(expression->unary.value)
- || is_address_constant(expression->unary.value));
+ expression_classification_t const expr = is_constant_expression(expression->unary.value);
+ expression_classification_t const addr = is_address_constant(expression->unary.value);
+ return expr > addr ? expr : addr;
}
case EXPR_BINARY_ADD:
case EXPR_BINARY_SUB: {
- expression_t *left = expression->binary.left;
- expression_t *right = expression->binary.right;
-
- if (is_type_pointer(skip_typeref(left->base.type))) {
- return is_address_constant(left) && is_constant_expression(right);
- } else if (is_type_pointer(skip_typeref(right->base.type))) {
- return is_constant_expression(left) && is_address_constant(right);
+ expression_t *const left = expression->binary.left;
+ expression_t *const right = expression->binary.right;
+ type_t *const ltype = skip_typeref(left->base.type);
+ type_t *const rtype = skip_typeref(right->base.type);
+
+ if (is_type_pointer(ltype)) {
+ expression_classification_t const l = is_address_constant(left);
+ expression_classification_t const r = is_constant_expression(right);
+ return l < r ? l : r;
+ } else if (is_type_pointer(rtype)) {
+ expression_classification_t const l = is_constant_expression(left);
+ expression_classification_t const r = is_address_constant(right);
+ return l < r ? l : r;
+ } else if (!is_type_valid(ltype) || !is_type_valid(rtype)) {
+ return EXPR_CLASS_ERROR;
+ } else {
+ return EXPR_CLASS_VARIABLE;
}
-
- return false;
}
case EXPR_REFERENCE: {
entity_t *entity = expression->reference.entity;
if (!is_declaration(entity))
- return false;
+ return EXPR_CLASS_VARIABLE;
type_t *type = skip_typeref(entity->declaration.type);
if (is_type_function(type))
- return true;
+ return EXPR_CLASS_CONSTANT;
if (is_type_array(type)) {
return is_object_with_linker_constant_address(expression);
}
/* Prevent stray errors */
if (!is_type_valid(type))
- return true;
- return false;
+ return EXPR_CLASS_ERROR;
+ return EXPR_CLASS_VARIABLE;
}
case EXPR_ARRAY_ACCESS: {
type_t *const type =
skip_typeref(revert_automatic_type_conversion(expression));
- return
- is_type_array(type) &&
- is_constant_expression(expression->array_access.index) &&
- is_address_constant(expression->array_access.array_ref);
+ if (!is_type_array(type))
+ return EXPR_CLASS_VARIABLE;
+ expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
+ expression_classification_t const idx = is_constant_expression(expression->array_access.index);
+ return ref < idx ? ref : idx;
}
case EXPR_CONDITIONAL: {
expression_t *const c = expression->conditional.condition;
- if (!is_constant_expression(c))
- return false;
+ expression_classification_t const cclass = is_constant_expression(c);
+ if (cclass != EXPR_CLASS_CONSTANT)
+ return cclass;
if (fold_constant_to_bool(c)) {
expression_t const *const t = expression->conditional.true_expression;
}
}
+ case EXPR_INVALID:
+ return EXPR_CLASS_ERROR;
+
default:
- return false;
+ return EXPR_CLASS_VARIABLE;
}
}
* Check if the given expression is a call to a builtin function
* returning a constant result.
*/
-static bool is_builtin_const_call(const expression_t *expression)
+static expression_classification_t is_builtin_const_call(const expression_t *expression)
{
expression_t *function = expression->call.function;
if (function->kind != EXPR_REFERENCE)
- return false;
+ return EXPR_CLASS_VARIABLE;
reference_expression_t *ref = &function->reference;
if (ref->entity->kind != ENTITY_FUNCTION)
- return false;
+ return EXPR_CLASS_VARIABLE;
switch (ref->entity->function.btk) {
case bk_gnu_builtin_huge_val:
case bk_gnu_builtin_nan:
case bk_gnu_builtin_nanf:
case bk_gnu_builtin_nanl:
- return true;
+ return EXPR_CLASS_CONSTANT;
default:
- return false;
+ return EXPR_CLASS_VARIABLE;
}
}
-static bool is_constant_pointer(const expression_t *expression)
+static expression_classification_t is_constant_pointer(const expression_t *expression)
{
- if (is_constant_expression(expression))
- return true;
+ expression_classification_t const expr_class = is_constant_expression(expression);
+ if (expr_class != EXPR_CLASS_VARIABLE)
+ return expr_class;
switch (expression->kind) {
case EXPR_UNARY_CAST:
return is_constant_pointer(expression->unary.value);
default:
- return false;
+ return EXPR_CLASS_VARIABLE;
}
}
-static bool is_object_with_constant_address(const expression_t *expression)
+static expression_classification_t is_object_with_constant_address(const expression_t *expression)
{
switch (expression->kind) {
case EXPR_SELECT: {
case EXPR_ARRAY_ACCESS: {
array_access_expression_t const* const array_access =
&expression->array_access;
- return
- is_constant_expression(array_access->index) && (
- is_object_with_constant_address(array_access->array_ref) ||
- is_constant_pointer(array_access->array_ref)
- );
+ expression_classification_t const idx_class = is_constant_expression(array_access->index);
+ 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);
+ return ref_addr > ref_ptr ? ref_addr : ref_ptr;
}
case EXPR_UNARY_DEREFERENCE:
return is_constant_pointer(expression->unary.value);
+
+ case EXPR_INVALID:
+ return EXPR_CLASS_ERROR;
+
default:
- return false;
+ return EXPR_CLASS_VARIABLE;
}
}
-bool is_constant_expression(const expression_t *expression)
+expression_classification_t is_constant_expression(const expression_t *expression)
{
switch (expression->kind) {
EXPR_LITERAL_CASES
case EXPR_BUILTIN_CONSTANT_P:
case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
case EXPR_REFERENCE_ENUM_VALUE:
- return true;
+ return EXPR_CLASS_CONSTANT;
case EXPR_SIZEOF: {
type_t *const type = skip_typeref(expression->typeprop.type);
- return !is_type_array(type) || !type->array.is_vla;
+ return
+ !is_type_array(type) || !type->array.is_vla ? EXPR_CLASS_CONSTANT :
+ EXPR_CLASS_VARIABLE;
}
case EXPR_STRING_LITERAL:
case EXPR_BINARY_BITWISE_OR_ASSIGN:
case EXPR_BINARY_COMMA:
case EXPR_ARRAY_ACCESS:
- return false;
+ return EXPR_CLASS_VARIABLE;
case EXPR_UNARY_TAKE_ADDRESS:
return is_object_with_constant_address(expression->unary.value);
return is_constant_expression(expression->unary.value);
case EXPR_UNARY_CAST:
- case EXPR_UNARY_CAST_IMPLICIT:
- return is_type_scalar(skip_typeref(expression->base.type))
- && is_constant_expression(expression->unary.value);
+ case EXPR_UNARY_CAST_IMPLICIT: {
+ type_t *const type = skip_typeref(expression->base.type);
+ if (is_type_scalar(type))
+ return is_constant_expression(expression->unary.value);
+ if (!is_type_valid(type))
+ return EXPR_CLASS_ERROR;
+ return EXPR_CLASS_VARIABLE;
+ }
case EXPR_BINARY_ADD:
case EXPR_BINARY_SUB:
case EXPR_BINARY_ISLESS:
case EXPR_BINARY_ISLESSEQUAL:
case EXPR_BINARY_ISLESSGREATER:
- case EXPR_BINARY_ISUNORDERED:
- return is_constant_expression(expression->binary.left)
- && is_constant_expression(expression->binary.right);
+ case EXPR_BINARY_ISUNORDERED: {
+ expression_classification_t const l = is_constant_expression(expression->binary.left);
+ expression_classification_t const r = is_constant_expression(expression->binary.right);
+ return l < r ? l : r;
+ }
case EXPR_BINARY_LOGICAL_AND: {
- expression_t const *const left = expression->binary.left;
- if (!is_constant_expression(left))
- return false;
+ expression_t const *const left = expression->binary.left;
+ expression_classification_t const lclass = is_constant_expression(left);
+ if (lclass != EXPR_CLASS_CONSTANT)
+ return lclass;
if (fold_constant_to_bool(left) == false)
- return true;
+ return EXPR_CLASS_CONSTANT;
return is_constant_expression(expression->binary.right);
}
case EXPR_BINARY_LOGICAL_OR: {
- expression_t const *const left = expression->binary.left;
- if (!is_constant_expression(left))
- return false;
+ expression_t const *const left = expression->binary.left;
+ expression_classification_t const lclass = is_constant_expression(left);
+ if (lclass != EXPR_CLASS_CONSTANT)
+ return lclass;
if (fold_constant_to_bool(left) == true)
- return true;
+ return EXPR_CLASS_CONSTANT;
return is_constant_expression(expression->binary.right);
}
return is_constant_initializer(expression->compound_literal.initializer);
case EXPR_CONDITIONAL: {
- expression_t *condition = expression->conditional.condition;
- if (!is_constant_expression(condition))
- return false;
+ 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) == true) {
expression_t const *const t = expression->conditional.true_expression;
- return t == NULL || is_constant_expression(t);
+ return t == NULL ? EXPR_CLASS_CONSTANT : is_constant_expression(t);
} else {
return is_constant_expression(expression->conditional.false_expression);
}
}
case EXPR_INVALID:
- return true;
+ return EXPR_CLASS_ERROR;
case EXPR_UNKNOWN:
break;
void change_indent(int delta);
void *allocate_ast(size_t size);
+typedef enum expression_classification_t {
+ EXPR_CLASS_VARIABLE,
+ EXPR_CLASS_ERROR,
+ EXPR_CLASS_CONSTANT
+} expression_classification_t;
+
/**
* Returns true if a given expression is a compile time
* constant. §6.6
*
* @param expression the expression to check
*/
-bool is_constant_initializer(const initializer_t *initializer);
+expression_classification_t is_constant_initializer(const initializer_t *initializer);
/**
* Returns true if a given expression is a compile time
*
* @param expression the expression to check
*/
-bool is_constant_expression(const expression_t *expression);
+expression_classification_t is_constant_expression(const expression_t *expression);
/**
* An object with a fixed but at compiletime unknown adress which will be known
* at link/load time.
*/
-bool is_address_constant(const expression_t *expression);
+expression_classification_t is_address_constant(const expression_t *expression);
long fold_constant_to_int(const expression_t *expression);
bool fold_constant_to_bool(const expression_t *expression);
}
expression_t *con;
- if (is_local_variable(op1) && is_constant_expression(op2)) {
+ if (is_local_variable(op1) && is_constant_expression(op2) == EXPR_CLASS_CONSTANT) {
var = op1->reference.entity;
con = op2;
- } else if (is_constant_expression(op1) && is_local_variable(op2)) {
+ } else if (is_constant_expression(op1) == EXPR_CLASS_CONSTANT && is_local_variable(op2)) {
cmp_val = get_inversed_pnc(cmp_val);
var = op2->reference.entity;
con = op1;
type_t *type = skip_typeref(expression->base.type);
ir_mode *mode = get_ir_mode_arithmetic(type);
- if (is_constant_expression(expression->left)) {
+ if (is_constant_expression(expression->left) == EXPR_CLASS_CONSTANT) {
bool val = fold_constant_to_bool(expression->left);
expression_kind_t ekind = expression->base.kind;
assert(ekind == EXPR_BINARY_LOGICAL_AND || ekind == EXPR_BINARY_LOGICAL_OR);
}
}
- if (is_constant_expression(expression->right)) {
+ if (is_constant_expression(expression->right) == EXPR_CLASS_CONSTANT) {
bool valr = fold_constant_to_bool(expression->right);
return valr ?
new_Const(get_mode_one(mode)) :
init_ir_types();
- assert(is_constant_expression(expression));
+ assert(is_constant_expression(expression) == EXPR_CLASS_CONSTANT);
ir_graph *old_current_ir_graph = current_ir_graph;
current_ir_graph = get_const_code_irg();
dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
/* first try to fold a constant condition */
- if (is_constant_expression(expression->condition)) {
+ if (is_constant_expression(expression->condition) == EXPR_CLASS_CONSTANT) {
bool val = fold_constant_to_bool(expression->condition);
if (val) {
expression_t *true_expression = expression->true_expression;
ir_mode *mode = get_ir_mode_arithmetic(expression->base.type);
long v;
- if (is_constant_expression(expression->value)) {
+ if (is_constant_expression(expression->value) == EXPR_CLASS_CONSTANT) {
v = 1;
} else {
v = 0;
return res;
}
- if (is_constant_expression(expression)) {
+ if (is_constant_expression(expression) == EXPR_CLASS_CONSTANT) {
ir_node *res = _expression_to_firm(expression);
ir_mode *mode = get_ir_mode_arithmetic(expression->base.type);
assert(is_Const(res));
/* set branch prediction info based on __builtin_expect */
if (is_builtin_expect(expression) && is_Cond(cond)) {
call_argument_t *argument = expression->call.arguments->next;
- if (is_constant_expression(argument->expression)) {
+ if (is_constant_expression(argument->expression) == EXPR_CLASS_CONSTANT) {
bool cnst = fold_constant_to_bool(argument->expression);
cond_jmp_predicate pred;
return;
}
- if (!is_constant_initializer(initializer)) {
+ if (is_constant_initializer(initializer) == EXPR_CLASS_VARIABLE) {
bool old_initializer_use_bitfield_basetype
= initializer_use_bitfield_basetype;
initializer_use_bitfield_basetype = true;
ir_node * body_block;
ir_node * false_block;
expression_t *const cond = statement->condition;
- if (is_constant_expression(cond) && fold_constant_to_bool(cond)) {
+ if (is_constant_expression(cond) == EXPR_CLASS_CONSTANT &&
+ fold_constant_to_bool(cond)) {
/* Shortcut for while (true). */
body_block = header_block;
false_block = NULL;
}
type_t *const type = skip_typeref(expression->base.type);
- return
- is_type_integer(type) &&
- is_constant_expression(expression) &&
- !fold_constant_to_bool(expression);
+ 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;
+ }
}
/**
{
expression_t *result = parse_subexpression(PREC_CONDITIONAL);
- if (!is_constant_expression(result)) {
+ if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
errorf(&result->base.source_position,
"expression '%E' is not constant", result);
}
*/
static bool is_initializer_constant(const expression_t *expression)
{
- return is_constant_expression(expression)
- || is_address_constant(expression);
+ return
+ is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+ is_address_constant(expression) != EXPR_CLASS_VARIABLE;
}
/**
array_type->array.size_expression = size_expression;
if (size_expression != NULL) {
- if (is_constant_expression(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
- * have a value greater than zero. */
- if (size <= 0) {
- if (size < 0 || !GNU_MODE) {
- errorf(&size_expression->base.source_position,
- "size of array must be greater than zero");
- } else if (warning.other) {
- warningf(&size_expression->base.source_position,
- "zero length arrays are a GCC extension");
+ switch (is_constant_expression(size_expression)) {
+ case EXPR_CLASS_CONSTANT: {
+ 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
+ * have a value greater than zero. */
+ if (size <= 0) {
+ if (size < 0 || !GNU_MODE) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero");
+ } else if (warning.other) {
+ warningf(&size_expression->base.source_position,
+ "zero length arrays are a GCC extension");
+ }
}
+ break;
}
- } else {
- array_type->array.is_vla = true;
+
+ case EXPR_CLASS_VARIABLE:
+ array_type->array.is_vla = true;
+ break;
+
+ case EXPR_CLASS_ERROR:
+ break;
}
}
static int determine_truth(expression_t const* const cond)
{
return
- !is_constant_expression(cond) ? 0 :
- fold_constant_to_bool(cond) ? 1 :
+ is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
+ fold_constant_to_bool(cond) ? 1 :
-1;
}
if (!expression_returns(expr))
return;
- if (is_constant_expression(expr)) {
+ if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
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) {
bit_size = get_type_size(base_type) * 8;
}
- if (is_constant_expression(size)) {
+ if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
long v = fold_constant_to_int(size);
const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
/* argument must be constant */
call_argument_t *argument = call->arguments;
- if (! is_constant_expression(argument->expression)) {
+ if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
break;
call_argument_t *arg = call->arguments->next;
- if (arg != NULL && ! is_constant_expression(arg->expression)) {
+ if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"second argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
call_argument_t *locality = NULL;
if (rw != NULL) {
- if (! is_constant_expression(rw->expression)) {
+ if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"second argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
locality = rw->next;
}
if (locality != NULL) {
- if (! is_constant_expression(locality->expression)) {
+ if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
"third argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
expression_t const *const right = expression->right;
/* The type of the right operand can be different for /= */
- if (is_type_integer(right->base.type) &&
- is_constant_expression(right) &&
+ if (is_type_integer(right->base.type) &&
+ is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
!fold_constant_to_bool(right)) {
warningf(&expression->base.source_position, "division by zero");
}
type_left = promote_integer(type_left);
- if (is_constant_expression(right)) {
+ if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
long count = fold_constant_to_int(right);
if (count < 0) {
warningf(&right->base.source_position,
static bool maybe_negative(expression_t const *const expr)
{
- return
- !is_constant_expression(expr) ||
- fold_constant_to_int(expr) < 0;
+ switch (is_constant_expression(expr)) {
+ case EXPR_CLASS_ERROR: return false;
+ case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+ default: return true;
+ }
}
/**
expression_t *const expression = parse_expression();
statement->case_label.expression = expression;
- if (!is_constant_expression(expression)) {
- /* This check does not prevent the error message in all cases of an
- * prior error while parsing the expression. At least it catches the
- * common case of a mistyped enum entry. */
- if (is_type_valid(skip_typeref(expression->base.type))) {
+ expression_classification_t const expr_class = is_constant_expression(expression);
+ if (expr_class != EXPR_CLASS_CONSTANT) {
+ if (expr_class != EXPR_CLASS_ERROR) {
errorf(pos, "case label does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
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)) {
- /* This check does not prevent the error message in all cases of an
- * prior error while parsing the expression. At least it catches the
- * common case of a mistyped enum entry. */
- if (is_type_valid(skip_typeref(end_range->base.type))) {
+ expression_classification_t const end_class = is_constant_expression(end_range);
+ if (end_class != EXPR_CLASS_CONSTANT) {
+ if (end_class != EXPR_CLASS_ERROR) {
errorf(pos, "case range does not reduce to an integer constant");
}
statement->case_label.is_bad = true;