Implement P0961
authorVille Voutilainen <ville.voutilainen@gmail.com>
Thu, 5 Apr 2018 14:37:18 +0000 (17:37 +0300)
committerVille Voutilainen <ville@gcc.gnu.org>
Thu, 5 Apr 2018 14:37:18 +0000 (17:37 +0300)
gcc/cp

Implement P0961
* decl.c (get_tuple_decomp_init): Check the templatedness
of a member get.

testsuite/

Implement P0961
* g++.dg/cpp1z/decomp10.C: Adjust.
* g++.dg/cpp1z/decomp37.C: New.

From-SVN: r259128

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

index 99ec3ea171e745ef65195d4e6a1a73d8c8b89d2a..090190612851fbebdb4a10c94d8dbac3fb1e8d74 100644 (file)
@@ -1,3 +1,9 @@
+2018-04-05  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+       Implement P0961
+       * decl.c (get_tuple_decomp_init): Check the templatedness
+       of a member get.
+
 2018-04-05  Jason Merrill  <jason@redhat.com>
 
        PR c++/85200 - ICE with constexpr if in generic lambda.
index 746084c90067f60abccb485517672f7d73b2b23c..31d9c983e9f380044c62dfcfe9e5f8d1ba22ed24 100644 (file)
@@ -7432,7 +7432,27 @@ get_tuple_decomp_init (tree decl, unsigned i)
 
   tree fns = lookup_qualified_name (TREE_TYPE (e), get_id,
                                    /*type*/false, /*complain*/false);
-  if (fns != error_mark_node)
+  bool use_member_get = false;
+
+  /* To use a member get, member lookup must find at least one
+     declaration that is a function template
+     whose first template parameter is a non-type parameter.  */
+  for (lkp_iterator iter (MAYBE_BASELINK_FUNCTIONS (fns)); iter; ++iter)
+    {
+      tree fn = *iter;
+      if (TREE_CODE (fn) == TEMPLATE_DECL)
+       {
+         tree tparms = DECL_TEMPLATE_PARMS (fn);
+         tree parm = TREE_VEC_ELT (INNERMOST_TEMPLATE_PARMS (tparms), 0);
+         if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL)
+           {
+             use_member_get = true;
+             break;
+           }
+       }
+    }
+
+  if (use_member_get)
     {
       fns = lookup_template_function (fns, targs);
       return build_new_method_call (e, fns, /*args*/NULL,
index 6ed9272a2f4c02e348559c809018999c940deb3c..b4169d343204700bc4b2d8c3eef7773f9b00b484 100644 (file)
@@ -20,7 +20,7 @@ void f3() { auto [ x ] = a3; }        // { dg-error "get" }
 
 struct A3a { int i,j; int get(); } a3a;
 template<> struct std::tuple_size<A3a> { enum { value = 1 }; };
-void f3a() { auto [ x ] = a3a; }       // { dg-error "get<0>" }
+void f3a() { auto [ x ] = a3a; }       // { dg-error "get" }
 
 struct A3b { int i,j; } a3b;
 int get(A3b&&);
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp37.C b/gcc/testsuite/g++.dg/cpp1z/decomp37.C
new file mode 100644 (file)
index 0000000..dc47908
--- /dev/null
@@ -0,0 +1,62 @@
+// { dg-additional-options -std=c++17 }
+// { dg-do compile }
+
+#include <memory>
+#include <tuple>
+#include <string>
+
+struct X : private std::shared_ptr<int>
+{
+  std::string fun_payload;
+};
+
+template<int N> std::string& get(X& x)
+{
+  if constexpr(N==0) return x.fun_payload;
+}
+
+namespace std {
+  template<> class tuple_size<X> : public std::integral_constant<int, 1> {};
+  template<> class tuple_element<0, X> {public: using type = std::string;};
+}
+
+struct X2 : private std::shared_ptr<int>
+{
+  int fun_payload;
+  template <class T> void get();
+};
+
+template<int N> int& get(X2& x)
+{
+  if constexpr(N==0) return x.fun_payload;
+}
+
+namespace std {
+  template<> class tuple_size<X2> : public std::integral_constant<int, 1> {};
+  template<> class tuple_element<0, X2> {public: using type = int;};
+}
+
+class X3
+{
+  double fun_payload;
+public:
+  template <int N> double& get()
+  {
+    if constexpr(N==0) return fun_payload;
+  }
+};
+
+namespace std {
+  template<> class tuple_size<X3> : public std::integral_constant<int, 1> {};
+  template<> class tuple_element<0, X3> {public: using type = double;};
+}
+
+int main()
+{
+  X x;
+  auto& [b1] = x;
+  X2 x2;
+  auto& [b2] = x2;
+  X3 x3;
+  auto& [b3] = x3;
+}