Patchwork C++ PATCH for c++/47504 (bogus overflow error with constexpr)

login
register
mail settings
Submitter Jason Merrill
Date March 17, 2011, 10:02 p.m.
Message ID <4D8284F1.3040408@redhat.com>
Download mbox | patch
Permalink /patch/87440/
State New
Headers show

Comments

Jason Merrill - March 17, 2011, 10:02 p.m.
In this testcase, the fix for PR 25125 causes us to rewrite what starts 
as char(int(-1) - int(1)) to char((unsigned char)(-1) - (unsigned 
char)1) and thus char((unsigned char)254).  254 doesn't fit in char, so 
the result has TREE_OVERFLOW set even though the original expression was 
all signed and therefore shouldn't.

One issue here is that the rewriting creates this situation where it 
didn't exist before, so I think the rewriting is wrong.

But it's also the case that both C and C++ distinguish between 
arithmetic overflow (i.e. INT_MAX+1) which has undefined behavior, and 
conversion of a value that doesn't fit in the target type (i.e. 
char(254)), which has implementation-defined behavior.  So we should 
allow the latter in constant expressions, even if it was wrong of the 
compiler to introduce it.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit de85bc3224ebed6104076ea0e6218e202da1a64e
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Mar 17 15:33:40 2011 -0400

    	PR c++/47504
    	* semantics.c (cxx_eval_constant_expression) [NOP_EXPR]: Don't let
    	the conversion set TREE_OVERFLOW.

Patch

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index cafca56..b6d1008 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -6991,6 +6991,11 @@  cxx_eval_constant_expression (const constexpr_call *call, tree t,
 	     conversion.  */
 	  return fold (t);
 	r = fold_build1 (TREE_CODE (t), to, op);
+	/* Conversion of an out-of-range value has implementation-defined
+	   behavior; the language considers it different from arithmetic
+	   overflow, which is undefined.  */
+	if (TREE_OVERFLOW_P (r) && !TREE_OVERFLOW_P (op))
+	  TREE_OVERFLOW (r) = false;
       }
       break;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 598cae6..2d614ec 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -44,5 +44,4 @@  extern template struct A3<int, 510>;
 
 // Use.
 A3<int, 1111> a31;
-// FIXME should this be an error?
 A3<char, 9999> a32;		// { dg-warning "overflow" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-overflow2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-overflow2.C
new file mode 100644
index 0000000..5d5749c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-overflow2.C
@@ -0,0 +1,8 @@ 
+// PR c++/47504
+// { dg-options -std=c++0x }
+
+char constexpr sub(char arg)
+{ return char(arg - char(1)); }
+
+int main()
+{ static char constexpr m = sub(-1); }