Patchwork C++ PATCH for c++/56728 (ICE with bogus constexpr function)

login
register
mail settings
Submitter Jason Merrill
Date March 28, 2013, 6:09 p.m.
Message ID <5154875D.4030003@redhat.com>
Download mbox | patch
Permalink /patch/232157/
State New
Headers show

Comments

Jason Merrill - March 28, 2013, 6:09 p.m.
In this testcase we were crashing because after function argument 
substitution in the initialization for crashnkill we couldn't figure out 
how to simplify *(Inner*)4, so we went back to bridge2.  It certainly 
doesn't make sense for the initializer to refer to a parameter for a 
function called in the initializer, so the back end correctly blew up. 
The cxx_eval_indirect_ref hunk addresses this by returning the expanded 
version of the operand rather than the original one.

The other two hunks address the issue that the getInner function is not 
a valid constexpr function, because it involves a reinterpret_cast from 
integer to pointer.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 44cdacef5b56c91e2787f737f0ea90aa66790436
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Mar 27 14:16:14 2013 -0400

    	PR c++/56728
    	* semantics.c (potential_constant_expression_1) [NOP_EXPR]: Reject
    	conversion from integer to pointer.
    	(cxx_eval_constant_expression): Likewise.
    	(cxx_eval_indirect_ref): Use the folded operand if we still think
    	this might be constant.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 72b884e..0b8e2f7 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7661,6 +7661,8 @@  cxx_eval_indirect_ref (const constexpr_call *call, tree t,
 
   if (r == NULL_TREE)
     {
+      if (addr && op0 != orig_op0)
+	return build1 (INDIRECT_REF, TREE_TYPE (t), op0);
       if (!addr)
 	VERIFY_CONSTANT (t);
       return t;
@@ -8056,6 +8058,16 @@  cxx_eval_constant_expression (const constexpr_call *call, tree t,
 						non_constant_p, overflow_p);
 	if (*non_constant_p)
 	  return t;
+	if (POINTER_TYPE_P (TREE_TYPE (t))
+	    && TREE_CODE (op) == INTEGER_CST
+	    && !integer_zerop (op))
+	  {
+	    if (!allow_non_constant)
+	      error_at (EXPR_LOC_OR_HERE (t),
+			"reinterpret_cast from integer to pointer");
+	    *non_constant_p = true;
+	    return t;
+	  }
 	if (op == oldop)
 	  /* We didn't fold at the top so we could check for ptr-int
 	     conversion.  */
@@ -8452,6 +8464,15 @@  potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 	 may change to something more specific to type-punning (DR 1312).  */
       {
         tree from = TREE_OPERAND (t, 0);
+	if (POINTER_TYPE_P (TREE_TYPE (t))
+	    && TREE_CODE (from) == INTEGER_CST
+	    && !integer_zerop (from))
+	  {
+	    if (flags & tf_error)
+	      error_at (EXPR_LOC_OR_HERE (t),
+			"reinterpret_cast from integer to pointer");
+	    return false;
+	  }
         return (potential_constant_expression_1
 		(from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags));
       }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
new file mode 100644
index 0000000..69db98b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
@@ -0,0 +1,37 @@ 
+// PR c++/56728
+// { dg-require-effective-target c++11 }
+
+class B {
+public:
+  static B instance;
+  class Inner
+  {
+  public:
+    class Wuzi
+    {
+      unsigned int m;
+    } m_Class[3];
+    unsigned m_Int[4];
+  };
+
+  constexpr static Inner & getInner()
+  {
+    /* I am surprised this is considered a constexpr */
+    return *((Inner *)4);
+  } // { dg-error "reinterpret_cast" }
+};
+
+B B::instance;
+
+class A
+{
+public:
+  constexpr A(B &bridge, B::Inner &bridge2, unsigned char index)
+    : m_Bridge(bridge), m_Wuz(bridge2.m_Class[index])
+  {}
+
+  B &m_Bridge;
+  B::Inner::Wuzi &m_Wuz;
+};
+A works{B::instance, B::getInner(), 3};
+A crashnkill[1]{{B::instance, B::getInner(), 3}};