[PR85569] skip constexpr target_expr constructor dummy type conversion
authorAlexandre Oliva <aoliva@redhat.com>
Wed, 5 Dec 2018 06:47:11 +0000 (06:47 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Wed, 5 Dec 2018 06:47:11 +0000 (06:47 +0000)
The testcase is the work-around testcase for the PR; even that had
started failing.  The problem was that, when unqualifying the type of
a TARGET_EXPR, we'd create a variant of the type, then request the
conversion of the TARGET_EXPR_INITIAL to that variant type.  Though
the types are different pointer-wise, they're the same_type_p, so the
resulting modified expr compares cp_tree_equal to the original, which
maybe_constant_value flags as an error.  There's no reason to
construct an alternate TARGET_EXPR or CONSTRUCTOR just because of an
equivalent type, except for another spot that expected pointer
equality that would no longer be satisfied.  Without relaxing the
assert in constexpr_call_hasher::equal, g++.robertl/eb73.C would
trigger an assertion failure.

for  gcc/cp/ChangeLog

PR c++/85569
* constexpr.c (adjust_temp_type): Test for type equality with
same_type_p.
(constexpr_call_hasher::equal): Likewise.

for  gcc/testsuite/ChangeLog

PR c++/85569
* g++.dg/cpp1z/pr85569.C: New.

From-SVN: r266816

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1z/pr85569.C [new file with mode: 0644]

index 253af3ba1347a0a2296fc2aa6669a61571f9fd25..3958992a57a56561c4ced6c7ad5faba38ad442c3 100644 (file)
@@ -1,3 +1,10 @@
+2018-12-05  Alexandre Oliva <aoliva@redhat.com>
+
+       PR c++/85569
+       * constexpr.c (adjust_temp_type): Test for type equality with
+       same_type_p.
+       (constexpr_call_hasher::equal): Likewise.
+
 2018-12-04  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/84636
index 92fd2b2d9d59a56ff95f241dc171ca69bc3944d0..a668d14e8bf5c270e917d8dad9dbac18998fa585 100644 (file)
@@ -1060,7 +1060,7 @@ constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs)
     {
       tree lhs_arg = TREE_VALUE (lhs_bindings);
       tree rhs_arg = TREE_VALUE (rhs_bindings);
-      gcc_assert (TREE_TYPE (lhs_arg) == TREE_TYPE (rhs_arg));
+      gcc_assert (same_type_p (TREE_TYPE (lhs_arg), TREE_TYPE (rhs_arg)));
       if (!cp_tree_equal (lhs_arg, rhs_arg))
         return false;
       lhs_bindings = TREE_CHAIN (lhs_bindings);
@@ -1276,7 +1276,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
 static tree
 adjust_temp_type (tree type, tree temp)
 {
-  if (TREE_TYPE (temp) == type)
+  if (same_type_p (TREE_TYPE (temp), type))
     return temp;
   /* Avoid wrapping an aggregate value in a NOP_EXPR.  */
   if (TREE_CODE (temp) == CONSTRUCTOR)
index 4c98c4133abde030643a2bd71c0678081edfd90a..8b74eb02bfbd6a0910903c45e2ae3537a7a97698 100644 (file)
@@ -1,3 +1,8 @@
+2018-12-05  Alexandre Oliva <aoliva@redhat.com>
+
+       PR c++/85569
+       * g++.dg/cpp1z/pr85569.C: New.
+
 2018-12-05  Chenghua Xu  <paul.hua.gm@gmail.com>
 
        * gcc.target/mips/msa.c: Adjusted clti_<su>.df $wn,$wn,5
diff --git a/gcc/testsuite/g++.dg/cpp1z/pr85569.C b/gcc/testsuite/g++.dg/cpp1z/pr85569.C
new file mode 100644 (file)
index 0000000..aec5430
--- /dev/null
@@ -0,0 +1,93 @@
+// { dg-do compile { target c++17 } }
+
+#include <utility>
+#include <tuple>
+
+#define LIFT_FWD(x) std::forward<decltype(x)>(x)
+
+template <typename T>
+inline
+constexpr
+auto
+equal(
+  T &&t)
+{
+  return [t = std::forward<T>(t)](const auto& obj)
+    -> decltype(obj == t)
+    {
+      return obj == t;
+    };
+}
+
+template <typename F, typename T>
+struct is_tuple_invocable;
+
+template <typename F, typename ... Ts>
+struct is_tuple_invocable<F, std::tuple<Ts...>>
+{
+  using type = typename std::is_invocable<F, Ts...>::type;
+};
+
+template <typename F>
+inline
+constexpr
+auto
+compose(
+  F&& f
+)
+  noexcept
+-> F
+{
+  return std::forward<F>(f);
+}
+
+namespace detail {
+  template <typename F, typename Tail, typename ... T>
+  inline
+  constexpr
+  auto
+  compose(
+    std::true_type,
+    F&& f,
+    Tail&& tail,
+    T&& ... objs)
+  noexcept(noexcept(f(tail(std::forward<T>(objs)...))))
+  -> decltype(f(tail(std::forward<T>(objs)...)))
+  {
+    return f(tail(std::forward<T>(objs)...));
+  }
+}
+template <typename F, typename ... Fs>
+inline
+constexpr
+auto
+compose(
+  F&& f,
+  Fs&&... fs)
+{
+  return [f = std::forward<F>(f), tail = compose(std::forward<Fs>(fs)...)]
+    (auto&& ... objs)
+    -> decltype(detail::compose(typename std::is_invocable<decltype(compose(std::forward<Fs>(fs)...)), decltype(objs)...>::type{},
+                                f,
+                                compose(std::forward<Fs>(fs)...),
+                                LIFT_FWD(objs)...))
+  {
+    using tail_type = decltype(compose(std::forward<Fs>(fs)...));
+    
+#ifndef NOT_VIA_TUPLE
+    using args_type = std::tuple<decltype(objs)...>;
+    constexpr auto unitail = typename is_tuple_invocable<tail_type, args_type>::type{};
+#else
+    constexpr auto unitail = typename std::is_invocable<tail_type, decltype(objs)...>::type{};
+#endif
+
+    return detail::compose(unitail,  f, tail, LIFT_FWD(objs)...);
+  };
+}
+
+template <auto N>
+constexpr auto eq = equal(N);
+
+static_assert(compose(eq<3>,
+                     std::plus<>{})(1,2),
+              "compose is constexpr");