re PR c++/63885 (ICE in static assert of constexpr forwarding xvalue container member...
authorJason Merrill <jason@redhat.com>
Wed, 19 Nov 2014 22:06:26 +0000 (17:06 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 19 Nov 2014 22:06:26 +0000 (17:06 -0500)
PR c++/63885
* constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't
complain yet about a reference.
[TARGET_EXPR]: Handle TARGET_EXPR with addr == true.
[ADDR_EXPR]: Make sure we don't take the address of a CONSTRUCTOR.
(cxx_bind_parameters_in_call): In the new scheme addr is always false.
* typeck.c (build_address): Don't take the address of a CONSTRUCTOR.

From-SVN: r217815

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C [new file with mode: 0644]

index 6f947b4b81143c365dbc3630dc3d102b08f60005..8f21d8b114699a5585c1a64fdc3f8b6b144b4dcf 100644 (file)
@@ -1,5 +1,13 @@
 2014-11-19  Jason Merrill  <jason@redhat.com>
 
+       PR c++/63885
+       * constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't
+       complain yet about a reference.
+       [TARGET_EXPR]: Handle TARGET_EXPR with addr == true.
+       [ADDR_EXPR]: Make sure we don't take the address of a CONSTRUCTOR.
+       (cxx_bind_parameters_in_call): In the new scheme addr is always false.
+       * typeck.c (build_address): Don't take the address of a CONSTRUCTOR.
+
        PR c++/57979
        * init.c (decl_really_constant_value): Rename from
        integral_constant_value.
index 52685450edf3f4e97fae52288704fef9ebb22b21..41867b8dc287dac25579492ecda1e85b192bcbb5 100644 (file)
@@ -1061,6 +1061,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
          x = ctx->object;
          x = cp_build_addr_expr (x, tf_warning_or_error);
        }
+      bool addr = false;
       if (parms && DECL_BY_REFERENCE (parms) && !use_new_call)
        {
          /* cp_genericize made this a reference for argument passing, but
@@ -1071,9 +1072,9 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
          gcc_assert (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE);
          type = TREE_TYPE (type);
          x = convert_from_reference (x);
+         addr = true;
        }
-      arg = cxx_eval_constant_expression (ctx, x,
-                                         TREE_CODE (type) == REFERENCE_TYPE,
+      arg = cxx_eval_constant_expression (ctx, x, addr,
                                          non_constant_p, overflow_p);
       /* Don't VERIFY_CONSTANT here.  */
       if (*non_constant_p && ctx->quiet)
@@ -2854,6 +2855,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        r = *p;
       else if (addr)
        /* Defer in case this is only used for its type.  */;
+      else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+       /* Defer, there's no lvalue->rvalue conversion.  */;
       else if (is_empty_class (TREE_TYPE (t)))
        {
          /* If the class is empty, we aren't actually loading anything.  */
@@ -2934,6 +2937,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (!*non_constant_p)
        /* Adjust the type of the result to the type of the temporary.  */
        r = adjust_temp_type (TREE_TYPE (t), r);
+      if (addr)
+       {
+         tree slot = TARGET_EXPR_SLOT (t);
+         ctx->values->put (slot, r);
+         return slot;
+       }
       break;
 
     case INIT_EXPR:
@@ -2995,6 +3004,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        /* Don't VERIFY_CONSTANT here.  */
        if (*non_constant_p)
          return t;
+       gcc_checking_assert (TREE_CODE (op) != CONSTRUCTOR);
        /* This function does more aggressive folding than fold itself.  */
        r = build_fold_addr_expr_with_type (op, TREE_TYPE (t));
        if (TREE_CODE (r) == ADDR_EXPR && TREE_OPERAND (r, 0) == oldop)
index 53fe67afc90cd5a55b42b1d2b25f84b53e16d534..71568515389516a88cca5c30adfb4066482d8635 100644 (file)
@@ -5305,6 +5305,7 @@ build_address (tree t)
 {
   if (error_operand_p (t) || !cxx_mark_addressable (t))
     return error_mark_node;
+  gcc_checking_assert (TREE_CODE (t) != CONSTRUCTOR);
   t = build_fold_addr_expr (t);
   if (TREE_CODE (t) != ADDR_EXPR)
     t = rvalue (t);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref8.C
new file mode 100644 (file)
index 0000000..04de9c7
--- /dev/null
@@ -0,0 +1,61 @@
+// PR c++/63885
+// { dg-do compile { target c++11 } }
+
+template<class T> struct remove_reference { typedef T type; };
+template<class T> struct remove_reference<T&> { typedef T type; };
+template<class T> struct remove_reference<T&&> { typedef T type; };
+
+template<class T> struct is_lvalue_reference { static const bool value = false; };
+template<class T> struct is_lvalue_reference<T&> { static const bool value = true; };
+
+template <bool B, class U, class V> struct conditional;
+template <class U, class V> struct conditional<true, U, V> { typedef U type; };
+template <class U, class V> struct conditional<false, U, V> { typedef V type; };
+
+template<typename _Tp> constexpr _Tp&&
+forward(typename remove_reference<_Tp>::type& __t) noexcept
+{ return static_cast<_Tp&&>(__t); }
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename C> struct member_forward
+{
+    typedef typename remove_reference <C>::type::type T;
+    typedef typename conditional
+    <
+        is_lvalue_reference <C &&>::value,
+        T&,
+        T
+    >::type type;
+};
+
+template <typename C> using member_forward_t = typename member_forward <C>::type;
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <int  , typename  > struct __get;
+template <       typename T> struct __get <0, T>
+{
+    constexpr static auto value (T arg)
+     -> decltype ((forward <member_forward_t <T>> (arg.t)))
+    {
+        return     forward <member_forward_t <T>> (arg.t);
+    }
+};
+
+template <int N, typename T> constexpr auto get (T && arg)
+ -> decltype (__get <N, T &&>::value (forward <T> (arg)))
+{
+    return    __get <N, T &&>::value (forward <T> (arg));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename T> struct S
+{
+    typedef T type;
+    T t;
+
+    template <typename U> constexpr S (U && u) : t (forward <U> (u)) {}
+};
+static_assert (get <0> (S <int &&> (1)) == 1, ""); // g++ 4.9 passes, g++ trunk r217559 fails