re PR c++/85437 (member pointer static upcast rejected in a constexpr context)
authorJakub Jelinek <jakub@gcc.gnu.org>
Wed, 25 Apr 2018 07:10:16 +0000 (09:10 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 25 Apr 2018 07:10:16 +0000 (09:10 +0200)
PR c++/85437
PR c++/49171
* cp-tree.h (REINTERPRET_CAST_P): New.
* constexpr.c (cxx_eval_constant_expression) <case NOP_EXPR>:
Reject REINTERPET_CAST_P conversions.  Use cplus_expand_constant
for non-trivial PTRMEM_CST cases.
* typeck.c (build_nop_reinterpret): New.
(build_reinterpret_cast_1): Use it.  Set REINTERPRET_CAST_P on
NOP_EXPRs returned by cp_convert.

* g++.dg/cpp0x/addressof1.C: Make reinterpret cases runtime checks.
* g++.dg/cpp0x/constexpr-cast.C: Remove xfails
* g++.dg/cpp0x/constexpr-nullptr-2.C: Likewise.
* g++.dg/cpp0x/constexpr-pmf1.C: Check when optimized.
* g++.dg/cpp0x/pr85437-1.C: New.
* g++.dg/cpp0x/pr85437-2.C: New.
* g++.dg/cpp0x/pr85437-3.C: New.
* g++.dg/cpp0x/pr85437-4.C: New.

From-SVN: r259629

13 files changed:
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/addressof1.C
gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C
gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr-2.C
gcc/testsuite/g++.dg/cpp0x/constexpr-pmf1.C
gcc/testsuite/g++.dg/cpp0x/pr85437-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr85437-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr85437-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/pr85437-4.C [new file with mode: 0644]

index 365592f5657e5fbf90be462b700ac700e92f66ea..037870627f926752caa13a535553aa3ae3564691 100644 (file)
@@ -1,3 +1,15 @@
+2018-04-25  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/85437
+       PR c++/49171
+       * cp-tree.h (REINTERPRET_CAST_P): New.
+       * constexpr.c (cxx_eval_constant_expression) <case NOP_EXPR>:
+       Reject REINTERPET_CAST_P conversions.  Use cplus_expand_constant
+       for non-trivial PTRMEM_CST cases.
+       * typeck.c (build_nop_reinterpret): New.
+       (build_reinterpret_cast_1): Use it.  Set REINTERPRET_CAST_P on
+       NOP_EXPRs returned by cp_convert.
+
 2018-04-23  Jason Merrill  <jason@redhat.com>
 
        PR c++/69560 - wrong alignof(double) on x86.
index 82f14baaefde1be1e8dfadf54d5ec159b2a5370c..b4bcc6a567d02cfe4485cdffe685a08ecb6a6fdc 100644 (file)
@@ -1822,8 +1822,8 @@ reduced_constant_expression_p (tree t)
 }
 
 /* Some expressions may have constant operands but are not constant
-   themselves, such as 1/0.  Call this function (or rather, the macro
-   following it) to check for that condition.
+   themselves, such as 1/0.  Call this function to check for that
+   condition.
 
    We only call this in places that require an arithmetic constant, not in
    places where we might have a non-constant expression that can be a
@@ -4579,9 +4579,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                                       non_constant_p, overflow_p);
       break;
 
+    case NOP_EXPR:
+      if (REINTERPRET_CAST_P (t))
+       {
+         if (!ctx->quiet)
+           error_at (EXPR_LOC_OR_LOC (t, input_location),
+                     "a reinterpret_cast is not a constant expression");
+         *non_constant_p = true;
+         return t;
+       }
+      /* FALLTHROUGH.  */
     case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
-    case NOP_EXPR:
     case UNARY_PLUS_EXPR:
       {
        tree oldop = TREE_OPERAND (t, 0);
@@ -4595,20 +4604,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        if (TREE_CODE (op) == PTRMEM_CST
            && !TYPE_PTRMEM_P (type))
          op = cplus_expand_constant (op);
+
        if (TREE_CODE (op) == PTRMEM_CST && tcode == NOP_EXPR)
          {
-           if (same_type_ignoring_top_level_qualifiers_p (type,
-                                                          TREE_TYPE (op))
-               || can_convert_qual (type, op))
-             return cp_fold_convert (type, op);
-           else
-             {
-               if (!ctx->quiet)
-                 error_at (EXPR_LOC_OR_LOC (t, input_location),
-                           "a reinterpret_cast is not a constant expression");
-               *non_constant_p = true;
-               return t;
-             }
+           if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (op))
+               && !can_convert_qual (type, op))
+             op = cplus_expand_constant (op);
+           return cp_fold_convert (type, op);
          }
 
        if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
@@ -4653,14 +4655,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                return t;
              }
          }
+
        if (op == oldop && tcode != UNARY_PLUS_EXPR)
          /* We didn't fold at the top so we could check for ptr-int
             conversion.  */
          return fold (t);
+
        if (tcode == UNARY_PLUS_EXPR)
          r = fold_convert (TREE_TYPE (t), op);
        else
          r = fold_build1 (tcode, type, op);
+
        /* Conversion of an out-of-range value has implementation-defined
           behavior; the language considers it different from arithmetic
           overflow, which is undefined.  */
index 37770770acbeeb95217135c92b4a57151065be22..72e4080b8332c7f0b0298126ba815116df4478dd 100644 (file)
@@ -372,6 +372,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM)
       DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL)
       SWITCH_STMT_ALL_CASES_P (in SWITCH_STMT)
+      REINTERPRET_CAST_P (in NOP_EXPR)
       ALIGNOF_EXPR_STD_P (in ALIGNOF_EXPR)
    1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
@@ -632,6 +633,11 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
 #define COND_EXPR_IS_VEC_DELETE(NODE) \
   TREE_LANG_FLAG_0 (COND_EXPR_CHECK (NODE))
 
+/* Nonzero if this NOP_EXPR is a reinterpret_cast.  Such conversions
+   are not constexprs.  Other NOP_EXPRs are.  */
+#define REINTERPRET_CAST_P(NODE)               \
+  TREE_LANG_FLAG_0 (NOP_EXPR_CHECK (NODE))
+
 /* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual
    sense of `same'.  */
 #define same_type_p(TYPE1, TYPE2) \
index 01baf6c17a39e36bc13c5abed827c9648039c3d1..907d31d9786c8eeceba74d98190117f9a2779cd5 100644 (file)
@@ -7280,6 +7280,18 @@ convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain)
   return build_nop (type, expr);
 }
 
+/* Build a NOP_EXPR to TYPE, but mark it as a reinterpret_cast so that
+   constexpr evaluation knows to reject it.  */
+
+static tree
+build_nop_reinterpret (tree type, tree expr)
+{
+  tree ret = build_nop (type, expr);
+  if (ret != expr)
+    REINTERPRET_CAST_P (ret) = true;
+  return ret;
+}
+
 /* Return a representation for a reinterpret_cast from EXPR to TYPE.
    If C_CAST_P is true, this reinterpret cast is being done as part of
    a C-style cast.  If VALID_P is non-NULL, *VALID_P is set to
@@ -7414,7 +7426,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
        warning (OPT_Wcast_function_type,
                 "cast between incompatible function types"
                 " from %qH to %qI", intype, type);
-      return build_nop (type, expr);
+      return build_nop_reinterpret (type, expr);
     }
   else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
     {
@@ -7425,7 +7437,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
        warning (OPT_Wcast_function_type,
                 "cast between incompatible pointer to member types"
                 " from %qH to %qI", intype, type);
-      return build_nop (type, expr);
+      return build_nop_reinterpret (type, expr);
     }
   else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
           || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
@@ -7451,7 +7463,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
        /* strict_aliasing_warning STRIP_NOPs its expr.  */
        strict_aliasing_warning (EXPR_LOCATION (expr), type, expr);
 
-      return build_nop (type, expr);
+      return build_nop_reinterpret (type, expr);
     }
   else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
           || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
@@ -7462,7 +7474,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
        warning (OPT_Wconditionally_supported,
                 "casting between pointer-to-function and pointer-to-object "
                 "is conditionally-supported");
-      return build_nop (type, expr);
+      return build_nop_reinterpret (type, expr);
     }
   else if (VECTOR_TYPE_P (type))
     return convert_to_vector (type, expr);
@@ -7478,7 +7490,11 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
       return error_mark_node;
     }
 
-  return cp_convert (type, expr, complain);
+  expr = cp_convert (type, expr, complain);
+  if (TREE_CODE (expr) == NOP_EXPR)
+    /* Mark any nop_expr that created as a reintepret_cast.  */
+    REINTERPRET_CAST_P (expr) = true;
+  return expr;
 }
 
 tree
index 6ba8fede06b111d709cdbd4e26626c3d3a3a5e1f..7a955a68c3eceb5d036aa98facf692c8f03c4c54 100644 (file)
@@ -1,3 +1,17 @@
+2018-04-25  Nathan Sidwell  <nathan@acm.org>
+           Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/85437
+       PR c++/49171
+       * g++.dg/cpp0x/addressof1.C: Make reinterpret cases runtime checks.
+       * g++.dg/cpp0x/constexpr-cast.C: Remove xfails
+       * g++.dg/cpp0x/constexpr-nullptr-2.C: Likewise.
+       * g++.dg/cpp0x/constexpr-pmf1.C: Check when optimized.
+       * g++.dg/cpp0x/pr85437-1.C: New.
+       * g++.dg/cpp0x/pr85437-2.C: New.
+       * g++.dg/cpp0x/pr85437-3.C: New.
+       * g++.dg/cpp0x/pr85437-4.C: New.
+
 2018-04-24  Steven G. Kargl  <kargl@gcc.gnu.org>
 
        PR fortran/85520
@@ -8,6 +22,7 @@
        PR target/85512
        * gcc.dg/pr85512.c: New test.
 
+2018-04-24  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/85485
        * g++.dg/cet-notrack-1.C (dg-options): Remove -mcet.
index 027811a82b576f425c7d411aaffad64b2534778a..be4b5e81d8971dbfda2f4894fb81243ffeaa35aa 100644 (file)
@@ -18,9 +18,7 @@ static_assert (addressof (j) == &i, "");
 
 struct S { int s; } s;
 static_assert (__builtin_addressof (s) == &s, "");
-static_assert ((int *) __builtin_addressof (s) == &s.s, "");
 static_assert (addressof (s) == &s, "");
-static_assert ((int *) addressof (s) == &s.s, "");
 
 struct T
 {
@@ -31,9 +29,7 @@ struct T
 };
 constexpr T t;
 T T::tt;
-static_assert (__builtin_addressof (t) == (const T *) &t.p, "");
 static_assert (&t == __builtin_addressof (T::tt), "");
-static_assert (addressof (t) == (const T *) &t.p, "");
 static_assert (&t == addressof (T::tt), "");
 
 struct S x, y;
@@ -76,8 +72,6 @@ constexpr int a = 1;
 static_assert (__builtin_addressof (a) == &a, "");
 static_assert (addressof (a) == &a, "");
 constexpr int c[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-static_assert ((const int *) __builtin_addressof (c) == &c[0], "");
-static_assert ((const int *) addressof (c) == &c[0], "");
 
 void
 baz ()
@@ -93,4 +87,15 @@ main ()
       || __builtin_addressof (baz) != baz
       || addressof (baz) != baz)
     __builtin_abort ();
+
+  // reinterpret casts are not constexprs
+  if (! (((int *) __builtin_addressof (s) == &s.s)
+        && ((int *) addressof (s) == &s.s)
+        && (__builtin_addressof (t) == (const T *) &t.p)
+        && (addressof (t) == (const T *) &t.p)
+        && ((const int *) __builtin_addressof (c) == &c[0])
+        && ((const int *) addressof (c) == &c[0])))
+    __builtin_abort ();
+
+  return 0;
 }
index 1ed01c88ff59898d30e2f34436e2393ecda40761..e0c7ed33ac7159304fea4b6f493cf4c344e2b7f0 100644 (file)
@@ -4,8 +4,8 @@
 
 int i;
 
-// The following is accepted due to bug 49171.
-constexpr void *q = reinterpret_cast<void*>(&i);    // { dg-error "" "bug c++/49171" { xfail *-*-* } }
+// The following was accepted due to bug 49171.
+constexpr void *q = reinterpret_cast<void*>(&i);    // { dg-error "not a constant expression" }
 
 constexpr void *r0 = reinterpret_cast<void*>(1);    // { dg-error "not a constant expression|reinterpret_cast from integer to pointer" }
 constexpr void *r1 = reinterpret_cast<void*>(sizeof 'x');  // { dg-error ".reinterpret_cast<void\\*>\\(1\[ul\]\*\\). is not a constant expression" }
index 3b3f01adea3eac9b305f6f402e2e2d4a4688abda..afb4b37be5a369d3a5a5f026332754f08c5bda8c 100644 (file)
@@ -99,9 +99,8 @@ constexpr const volatile void* pv3 = p0;
 constexpr void* pv4 = static_cast<void*>(p0);
 constexpr const void* pv5 = static_cast<const void*>(p0);
 
-// The following should be rejected but isn't because of bug c++/49171
-// - [C++0x][constexpr] Constant expressions support reinterpret_cast
-constexpr void* pv6 = reinterpret_cast<void*>(p0);   // { dg-error "" "bug c++/49171" { xfail *-*-* } }
+// The following was accepted due to bug c++/49171
+constexpr void* pv6 = reinterpret_cast<void*>(p0);   // { dg-error "not a constant expression" }
 
 // Adding or subtracting zero from a null pointer is valid in C++.
 constexpr int* p1 = p0 + 0;
index b6a7935746f222b3016852002d85901e23420acc..84077f34adcb1676bc6534f87ddda3dfabb54852 100644 (file)
@@ -1,6 +1,6 @@
 // PR c++/77775
-// { dg-options -fdump-tree-gimple }
-// { dg-final { scan-tree-dump "== viewAdded" "gimple" { target c++11 } } }
+// { dg-options "-fdump-tree-fre1 -O1" }
+// { dg-final { scan-tree-dump "== viewAdded" "fre1" { target c++11 } } }
 
 namespace Sublime {
 struct View;
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-1.C b/gcc/testsuite/g++.dg/cpp0x/pr85437-1.C
new file mode 100644 (file)
index 0000000..a2f5dab
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/85437
+// { dg-do compile { target c++11 } }
+
+struct A { int a; constexpr A() : a(0) {} };
+struct B : A { int x; constexpr B() : x(0) {} };
+struct X { int z; constexpr X() : z(0) {} };
+struct C : X, B {};
+constexpr int C::*cbx = &B::x;
+constexpr int B::*bx = &B::x;
+constexpr int A::*abx = static_cast<int(A::*)>(&B::x); // { dg-bogus "not a constant expression" }
+
+constexpr const C y;
+constexpr const B& yb = y;
+constexpr const A& ya = y;
+constexpr int const *pcbx = &(y.*cbx);
+constexpr int const *pbx = &(y.*bx);
+constexpr int const *pabx = &(ya.*abx);
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C b/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C
new file mode 100644 (file)
index 0000000..a059e43
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/85437
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B : A { int x; };
+
+constexpr int A::*abx
+= reinterpret_cast<int(A::*)>(&B::x); // { dg-error "reinterpret.*constant" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C b/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C
new file mode 100644 (file)
index 0000000..eb0fd55
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/85437
+// { dg-do compile { target c++11 } }
+
+struct A { int y; };
+struct B { int x; };
+struct C : A, B {};
+constexpr int C::*pci = &B::x;
+constexpr int A::*pai = static_cast<int A::*>(static_cast<int C::*>(&B::x)); // { dg-bogus "not a constant expression" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-4.C b/gcc/testsuite/g++.dg/cpp0x/pr85437-4.C
new file mode 100644 (file)
index 0000000..e69607d
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/85437
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B { int x; };
+struct C : A, B {};
+constexpr int C::*pci = &B::x;
+constexpr int A::*pai = static_cast<int A::*>(pci);    // { dg-bogus "not a constant expression" }