Message ID | 675c0336.170a0220.274a.14d1@mx.google.com |
---|---|
State | New |
Headers | show |
Series | [v2] c++: Disallow decomposition of lambda bases [PR90321] | expand |
On 12/13/24 4:49 AM, Nathaniel Shead wrote: > On Thu, Nov 21, 2024 at 04:01:02PM -0500, Marek Polacek wrote: >> 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? >> > > Thanks, fixed. > >>> + 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. >> > > Yeah, I agree, thanks. Here's an updated version of the patch. > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? OK. > -- >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> > Reviewed-by: Marek Polacek <polacek@redhat.com> > --- > gcc/cp/decl.cc | 19 +++++++++++++------ > gcc/testsuite/g++.dg/cpp1z/decomp62.C | 12 ++++++++++++ > 2 files changed, 25 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 4ba6e3784ca..a1b9957a9be 100644 > --- a/gcc/cp/decl.cc > +++ b/gcc/cp/decl.cc > @@ -9405,6 +9405,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)) > + { > + auto_diagnostic_group d; > + error_at (loc, "cannot decompose lambda closure type %qT", type); > + inform (location_of (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 > @@ -9447,9 +9455,13 @@ 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 (location_of (type), "in base class of %qT", type); > + return error_mark_node; > + } > if (t != NULL_TREE && t != ret) > { > if (ret == type) > @@ -9905,11 +9917,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; > +}
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 4ba6e3784ca..a1b9957a9be 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -9405,6 +9405,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)) + { + auto_diagnostic_group d; + error_at (loc, "cannot decompose lambda closure type %qT", type); + inform (location_of (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 @@ -9447,9 +9455,13 @@ 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 (location_of (type), "in base class of %qT", type); + return error_mark_node; + } if (t != NULL_TREE && t != ret) { if (ret == type) @@ -9905,11 +9917,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; +}