diff options
author | Richard Henderson <rth@cygnus.com> | 1999-07-30 18:13:08 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 1999-07-30 18:13:08 -0700 |
commit | 7e8176d77891d6bfb95844e3918690ccbfcc7b71 (patch) | |
tree | 2f3e1a3cf22e4e54e7419196de2cc7403340bbb3 /gcc/c-common.c | |
parent | 96a0a146e23185b9e1dc2f369781ea88efd4120c (diff) | |
download | gcc-7e8176d77891d6bfb95844e3918690ccbfcc7b71.zip gcc-7e8176d77891d6bfb95844e3918690ccbfcc7b71.tar.gz gcc-7e8176d77891d6bfb95844e3918690ccbfcc7b71.tar.bz2 |
c-typeck.c (initializer_constant_valid_p): Move ...
* c-typeck.c (initializer_constant_valid_p): Move ...
* c-common.c (initializer_constant_valid_p): ... here. Use
FOO_TYPE_P instead of tests against TREE_CODE. Allow subtraction
of label addresses.
* c-common.h (initializer_constant_valid_p): Declare.
* c-tree.h (initializer_constant_valid_p): Remove.
From-SVN: r28349
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 4c083de..137d1d3 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -3767,3 +3767,159 @@ build_va_arg (expr, type) { return build1 (VA_ARG_EXPR, type, expr); } + +/* Return nonzero if VALUE is a valid constant-valued expression + for use in initializing a static variable; one that can be an + element of a "constant" initializer. + + Return null_pointer_node if the value is absolute; + if it is relocatable, return the variable that determines the relocation. + We assume that VALUE has been folded as much as possible; + therefore, we do not need to check for such things as + arithmetic-combinations of integers. */ + +tree +initializer_constant_valid_p (value, endtype) + tree value; + tree endtype; +{ + switch (TREE_CODE (value)) + { + case CONSTRUCTOR: + if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE) + && TREE_CONSTANT (value) + && CONSTRUCTOR_ELTS (value)) + return + initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)), + endtype); + + return TREE_STATIC (value) ? null_pointer_node : 0; + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + return null_pointer_node; + + case ADDR_EXPR: + return TREE_OPERAND (value, 0); + + case NON_LVALUE_EXPR: + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + case CONVERT_EXPR: + case NOP_EXPR: + /* Allow conversions between pointer types. */ + if (POINTER_TYPE_P (TREE_TYPE (value)) + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow conversions between real types. */ + if (FLOAT_TYPE_P (TREE_TYPE (value)) + && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow length-preserving conversions between integer types. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (value)) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))) + && (TYPE_PRECISION (TREE_TYPE (value)) + == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); + + /* Allow conversions between other integer types only if + explicit value. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (value)) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))) + { + tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + if (inner == null_pointer_node) + return null_pointer_node; + break; + } + + /* Allow (int) &foo provided int is as wide as a pointer. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (value)) + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))) + && (TYPE_PRECISION (TREE_TYPE (value)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + + /* Likewise conversions from int to pointers, but also allow + conversions from 0. */ + if (POINTER_TYPE_P (TREE_TYPE (value)) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))) + { + if (integer_zerop (TREE_OPERAND (value, 0))) + return null_pointer_node; + else if (TYPE_PRECISION (TREE_TYPE (value)) + <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + } + + /* Allow conversions to union types if the value inside is okay. */ + if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE) + return initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + break; + + case PLUS_EXPR: + if (! INTEGRAL_TYPE_P (endtype) + || TYPE_PRECISION (endtype) >= POINTER_SIZE) + { + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); + /* If either term is absolute, use the other terms relocation. */ + if (valid0 == null_pointer_node) + return valid1; + if (valid1 == null_pointer_node) + return valid0; + } + break; + + case MINUS_EXPR: + if (! INTEGRAL_TYPE_P (endtype) + || TYPE_PRECISION (endtype) >= POINTER_SIZE) + { + tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), + endtype); + tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1), + endtype); + /* Win if second argument is absolute. */ + if (valid1 == null_pointer_node) + return valid0; + /* Win if both arguments have the same relocation. + Then the value is absolute. */ + if (valid0 == valid1) + return null_pointer_node; + } + + /* Support differences between labels. */ + if (INTEGRAL_TYPE_P (endtype)) + { + tree op0, op1; + op0 = TREE_OPERAND (value, 0); + op1 = TREE_OPERAND (value, 1); + STRIP_NOPS (op0); + STRIP_NOPS (op1); + + if (TREE_CODE (op0) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL + && TREE_CODE (op1) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL) + return null_pointer_node; + } + break; + + default: + break; + } + + return 0; +} + |