diff mbox series

[C++] Implement P0961

Message ID CAFk2RUbrcZEzXt3UJKFY8hwzGPOz1-s0=S5vnXO9tw6L4DrZEQ@mail.gmail.com
State New
Headers show
Series [C++] Implement P0961 | expand

Commit Message

Ville Voutilainen April 4, 2018, 10:26 p.m. UTC
Tested on Linux-PPC64.

2018-04-05  Ville Voutilainen  <ville.voutilainen@gmail.com>

    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.

Comments

Jason Merrill April 5, 2018, 1:37 p.m. UTC | #1
On Wed, Apr 4, 2018 at 6:26 PM, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> +   tree parm = TREE_VEC_ELT (TREE_VALUE (tparms), 0);

I think you want to use INNERMOST_TEMPLATE_PARMS here rather than
TREE_VALUE directly.

Please also add a comment quoting the rule you're implementing.

Jason
Ville Voutilainen April 5, 2018, 2:06 p.m. UTC | #2
On 5 April 2018 at 16:37, Jason Merrill <jason@redhat.com> wrote:
> On Wed, Apr 4, 2018 at 6:26 PM, Ville Voutilainen
> <ville.voutilainen@gmail.com> wrote:
>> +   tree parm = TREE_VEC_ELT (TREE_VALUE (tparms), 0);
>
> I think you want to use INNERMOST_TEMPLATE_PARMS here rather than
> TREE_VALUE directly.
>
> Please also add a comment quoting the rule you're implementing.

Alright, here's a new patch.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 746084c..31d9c98 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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,
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp10.C b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
index 6ed9272..b4169d3 100644
--- a/gcc/testsuite/g++.dg/cpp1z/decomp10.C
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
@@ -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
index 0000000..dc47908
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp37.C
@@ -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;
+}
Jason Merrill April 5, 2018, 2:32 p.m. UTC | #3
OK, thanks.

On Thu, Apr 5, 2018 at 10:06 AM, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> On 5 April 2018 at 16:37, Jason Merrill <jason@redhat.com> wrote:
>> On Wed, Apr 4, 2018 at 6:26 PM, Ville Voutilainen
>> <ville.voutilainen@gmail.com> wrote:
>>> +   tree parm = TREE_VEC_ELT (TREE_VALUE (tparms), 0);
>>
>> I think you want to use INNERMOST_TEMPLATE_PARMS here rather than
>> TREE_VALUE directly.
>>
>> Please also add a comment quoting the rule you're implementing.
>
> Alright, here's a new patch.
diff mbox series

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 746084c..1a100c8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7432,7 +7432,24 @@  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;
+
+  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 (TREE_VALUE (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,
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp10.C b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
index 6ed9272..b4169d3 100644
--- a/gcc/testsuite/g++.dg/cpp1z/decomp10.C
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
@@ -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
index 0000000..dc47908
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp37.C
@@ -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;
+}