diff mbox series

c++: Disallow decomposition of lambda bases [PR90321]

Message ID 672c9b18.050a0220.2a5143.2862@mx.google.com
State New
Headers show
Series c++: Disallow decomposition of lambda bases [PR90321] | expand

Commit Message

Nathaniel Shead Nov. 7, 2024, 10:48 a.m. UTC
Bootstrapped and lightly regtested on x86_64-pc-linux-gnu (so far just
dg.exp), OK for trunk if full regtest succeeds?

-- >8 --

Decomposition of lambda closure types is not allowed by
[dcl.struct.bind] p6, since members of a closure have no name.

r244909 made this an error, but missed the case where a lambda is used
as a base.  This patch moves the check to find_decomp_class_base to
handle this case.

As a drive-by improvement, we also slightly improve the diagnostics to
indicate why a base class was being inspected.  Ideally the diagnostic
would point directly at the relevant base, but there doesn't seem to be
an easy way to get this location just from the binfo so I don't worry
about that here.

	PR c++/90321

gcc/cp/ChangeLog:

	* decl.cc (find_decomp_class_base): Check for decomposing a
	lambda closure type.  Report base class chains if needed.
	(cp_finish_decomp): Remove no-longer-needed check.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1z/decomp62.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/decl.cc                        | 20 ++++++++++++++------
 gcc/testsuite/g++.dg/cpp1z/decomp62.C | 12 ++++++++++++
 2 files changed, 26 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp62.C

Comments

Marek Polacek Nov. 21, 2024, 9:01 p.m. UTC | #1
On Thu, Nov 07, 2024 at 09:48:52PM +1100, Nathaniel Shead wrote:
> Bootstrapped and lightly regtested on x86_64-pc-linux-gnu (so far just
> dg.exp), OK for trunk if full regtest succeeds?
> 
> -- >8 --
> 
> Decomposition of lambda closure types is not allowed by
> [dcl.struct.bind] p6, since members of a closure have no name.
> 
> r244909 made this an error, but missed the case where a lambda is used
> as a base.  This patch moves the check to find_decomp_class_base to
> handle this case.
> 
> As a drive-by improvement, we also slightly improve the diagnostics to
> indicate why a base class was being inspected.  Ideally the diagnostic
> would point directly at the relevant base, but there doesn't seem to be
> an easy way to get this location just from the binfo so I don't worry
> about that here.
> 
> 	PR c++/90321
> 
> gcc/cp/ChangeLog:
> 
> 	* decl.cc (find_decomp_class_base): Check for decomposing a
> 	lambda closure type.  Report base class chains if needed.
> 	(cp_finish_decomp): Remove no-longer-needed check.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp1z/decomp62.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>  gcc/cp/decl.cc                        | 20 ++++++++++++++------
>  gcc/testsuite/g++.dg/cpp1z/decomp62.C | 12 ++++++++++++
>  2 files changed, 26 insertions(+), 6 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/decomp62.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 0e4533c6fab..87480dca1ac 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -9268,6 +9268,14 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
>  static tree
>  find_decomp_class_base (location_t loc, tree type, tree ret)
>  {
> +  if (LAMBDA_TYPE_P (type))
> +    {

Missing auto_diagnostic_group d; here?

> +      error_at (loc, "cannot decompose lambda closure type %qT", type);
> +      inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)),
> +	      "lambda declared here");
> +      return error_mark_node;
> +    }
> +
>    bool member_seen = false;
>    for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
>      if (TREE_CODE (field) != FIELD_DECL
> @@ -9310,9 +9318,14 @@ find_decomp_class_base (location_t loc, tree type, tree ret)
>    for (binfo = TYPE_BINFO (type), i = 0;
>         BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
>      {
> +      auto_diagnostic_group d;
>        tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret);
>        if (t == error_mark_node)
> -	return error_mark_node;
> +	{
> +	  inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)),

location_of might be nicer.

Otherwise looks fine to me, thanks!

> +		  "in base class of %qT", type);
> +	  return error_mark_node;
> +	}
>        if (t != NULL_TREE && t != ret)
>  	{
>  	  if (ret == type)
> @@ -9768,11 +9781,6 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
>        error_at (loc, "cannot decompose non-array non-class type %qT", type);
>        goto error_out;
>      }
> -  else if (LAMBDA_TYPE_P (type))
> -    {
> -      error_at (loc, "cannot decompose lambda closure type %qT", type);
> -      goto error_out;
> -    }
>    else if (processing_template_decl && complete_type (type) == error_mark_node)
>      goto error_out;
>    else if (processing_template_decl && !COMPLETE_TYPE_P (type))
> diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp62.C b/gcc/testsuite/g++.dg/cpp1z/decomp62.C
> new file mode 100644
> index 00000000000..b0ce10570c7
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/decomp62.C
> @@ -0,0 +1,12 @@
> +// PR c++/90321
> +// { dg-do compile { target c++17 } }
> +
> +template<class F> struct hack : F { };
> +template<class F> hack(F) -> hack<F>;
> +
> +int main()
> +{
> +    auto f = [x = 1, y = 2]() { };
> +    auto [a, b] = hack { f };  // { dg-error "cannot decompose lambda closure type" }
> +    return b;
> +}
> -- 
> 2.47.0
> 

Marek
diff mbox series

Patch

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 0e4533c6fab..87480dca1ac 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -9268,6 +9268,14 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 static tree
 find_decomp_class_base (location_t loc, tree type, tree ret)
 {
+  if (LAMBDA_TYPE_P (type))
+    {
+      error_at (loc, "cannot decompose lambda closure type %qT", type);
+      inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)),
+	      "lambda declared here");
+      return error_mark_node;
+    }
+
   bool member_seen = false;
   for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     if (TREE_CODE (field) != FIELD_DECL
@@ -9310,9 +9318,14 @@  find_decomp_class_base (location_t loc, tree type, tree ret)
   for (binfo = TYPE_BINFO (type), i = 0;
        BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
     {
+      auto_diagnostic_group d;
       tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret);
       if (t == error_mark_node)
-	return error_mark_node;
+	{
+	  inform (DECL_SOURCE_LOCATION (TYPE_NAME (type)),
+		  "in base class of %qT", type);
+	  return error_mark_node;
+	}
       if (t != NULL_TREE && t != ret)
 	{
 	  if (ret == type)
@@ -9768,11 +9781,6 @@  cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
       error_at (loc, "cannot decompose non-array non-class type %qT", type);
       goto error_out;
     }
-  else if (LAMBDA_TYPE_P (type))
-    {
-      error_at (loc, "cannot decompose lambda closure type %qT", type);
-      goto error_out;
-    }
   else if (processing_template_decl && complete_type (type) == error_mark_node)
     goto error_out;
   else if (processing_template_decl && !COMPLETE_TYPE_P (type))
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp62.C b/gcc/testsuite/g++.dg/cpp1z/decomp62.C
new file mode 100644
index 00000000000..b0ce10570c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp62.C
@@ -0,0 +1,12 @@ 
+// PR c++/90321
+// { dg-do compile { target c++17 } }
+
+template<class F> struct hack : F { };
+template<class F> hack(F) -> hack<F>;
+
+int main()
+{
+    auto f = [x = 1, y = 2]() { };
+    auto [a, b] = hack { f };  // { dg-error "cannot decompose lambda closure type" }
+    return b;
+}