aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/utils.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2008-05-13 08:46:18 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2008-05-13 08:46:18 +0000
commitf80cddcb5d45179f285da0a56a36db694935148d (patch)
treed5e33cde32652206851dc8984dcaa621347d97ff /gcc/ada/utils.c
parent8beaca66e37f300d7ca91beae79c0f4eb341f760 (diff)
downloadgcc-f80cddcb5d45179f285da0a56a36db694935148d.zip
gcc-f80cddcb5d45179f285da0a56a36db694935148d.tar.gz
gcc-f80cddcb5d45179f285da0a56a36db694935148d.tar.bz2
re PR ada/24880 (infinite loop on conversion of integer type with size clause)
PR ada/24880 PR ada/26635 * utils.c (convert) <INTEGER_TYPE>: When converting an additive expression to an integral type with lower precision, use NOP_EXPR directly in a couple of special cases. From-SVN: r135257
Diffstat (limited to 'gcc/ada/utils.c')
-rw-r--r--gcc/ada/utils.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/gcc/ada/utils.c b/gcc/ada/utils.c
index 202818d..b4b3894 100644
--- a/gcc/ada/utils.c
+++ b/gcc/ada/utils.c
@@ -3627,7 +3627,7 @@ convert (tree type, tree expr)
if (TYPE_FAT_POINTER_P (type) && !TYPE_FAT_POINTER_P (etype))
return convert_to_fat_pointer (type, expr);
- /* If we're converting between two aggregate types that are mere
+ /* If we are converting between two aggregate types that are mere
variants, just make a VIEW_CONVERT_EXPR. */
else if (code == ecode
&& AGGREGATE_TYPE_P (type)
@@ -3662,6 +3662,30 @@ convert (tree type, tree expr)
/* ... fall through ... */
case ENUMERAL_TYPE:
+ /* If we are converting an additive expression to an integer type
+ with lower precision, be wary of the optimization that can be
+ applied by convert_to_integer. There are 2 problematic cases:
+ - if the first operand was originally of a biased type,
+ because we could be recursively called to convert it
+ to an intermediate type and thus rematerialize the
+ additive operator endlessly,
+ - if the expression contains a placeholder, because an
+ intermediate conversion that changes the sign could
+ be inserted and thus introduce an artificial overflow
+ at compile time when the placeholder is substituted. */
+ if (code == INTEGER_TYPE
+ && ecode == INTEGER_TYPE
+ && TYPE_PRECISION (type) < TYPE_PRECISION (etype)
+ && (TREE_CODE (expr) == PLUS_EXPR || TREE_CODE (expr) == MINUS_EXPR))
+ {
+ tree op0 = get_unwidened (TREE_OPERAND (expr, 0), type);
+
+ if ((TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
+ && TYPE_BIASED_REPRESENTATION_P (TREE_TYPE (op0)))
+ || CONTAINS_PLACEHOLDER_P (expr))
+ return build1 (NOP_EXPR, type, expr);
+ }
+
return fold (convert_to_integer (type, expr));
case POINTER_TYPE: