* [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] @ 2022-05-26 18:34 Patrick Palka 2022-05-26 18:57 ` Patrick Palka 0 siblings, 1 reply; 15+ messages in thread From: Patrick Palka @ 2022-05-26 18:34 UTC (permalink / raw) To: gcc-patches Here we expect the calls to BaseClass::baseDevice resolve to the second, third and fourth overloads respectively in light of the cv-qualifiers of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first overload at instantiation time. This happens because the calls to BaseClass::baseDevice are all deemed non-dependent (ever since r7-755-g23cb72663051cd made us ignore the dependentness of 'this' when considering the dependence of a non-static memfn call), hence we end up checking the call ahead of time, using as the object argument a dummy object of type BaseClass. Since this object argument is cv-unqualified, the calls incoherently resolve to the first overload of baseDevice. Before r12-6075, this incorrect result would just get silently discarded and we'd end up redoing OR at instantiation time using 'this' as the object argument. But after r12-6075, we now reuse this incorrect result at instantiation time. This patch fixes this by making finish_call_expr request from maybe_dummy_object a cv-qualified object consistent with the cv-quals of 'this'. That way, ahead of time OR using a dummy object will give us the right answer and we could safely reuse it at instantiation time. NB: r7-755 is also the cause of the related issue PR105742. Not sure if there's a fix that could resolve both PRs at once.. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk/12? PR c++/105637 gcc/cp/ChangeLog: * semantics.cc (finish_call_expr): Pass a cv-qualified object type to maybe_dummy_object that is consistent with the cv-qualifiers of 'this' if available. gcc/testsuite/ChangeLog: * g++.dg/template/non-dependent23.C: New test. --- gcc/cp/semantics.cc | 15 ++++++++--- .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index cd7a2818feb..1d9348c6cf1 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, [class.access.base] says that we need to convert 'this' to B* as part of the access, so we pass 'B' to maybe_dummy_object. */ + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)); if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) { /* A constructor call always uses a dummy object. (This constructor call which has the form A::A () is actually invalid and we are going to reject it later in build_new_method_call.) */ - object = build_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn))); + object = build_dummy_object (object_type); } else - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), - NULL); + { + if (current_class_ref) + { + /* Make sure that if maybe_dummy_object gives us a dummy object, + it'll have the same cv-quals as '*this'. */ + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); + object_type = cp_build_qualified_type (object_type, quals); + } + object = maybe_dummy_object (object_type, NULL); + } result = build_new_method_call (object, fn, args, NULL_TREE, (disallow_virtual diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C new file mode 100644 index 00000000000..ef95c591b75 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C @@ -0,0 +1,25 @@ +// PR c++/105637 + +struct BaseClass { + void baseDevice(); // #1 + void baseDevice() const; // #2 + void baseDevice() volatile; // #3 + void baseDevice() const volatile; // #4 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() const { + BaseClass::baseDevice(); // should select #2, not #1 + } + + void failsToCompile() volatile { + BaseClass::baseDevice(); // should select #3, not #1 + } + + void failsToCompile() const volatile { + BaseClass::baseDevice(); // should select #4, not #1 + } +}; + +template struct TopClass<BaseClass>; -- 2.36.1.182.g6afdb07b7b ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-05-26 18:34 [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] Patrick Palka @ 2022-05-26 18:57 ` Patrick Palka 2022-05-26 20:39 ` Jason Merrill 0 siblings, 1 reply; 15+ messages in thread From: Patrick Palka @ 2022-05-26 18:57 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches, jason On Thu, 26 May 2022, Patrick Palka wrote: > Here we expect the calls to BaseClass::baseDevice resolve to the second, > third and fourth overloads respectively in light of the cv-qualifiers > of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the > calls incorrectly resolve to the first overload at instantiation time. > > This happens because the calls to BaseClass::baseDevice are all deemed > non-dependent (ever since r7-755-g23cb72663051cd made us ignore the > dependentness of 'this' when considering the dependence of a non-static > memfn call), hence we end up checking the call ahead of time, using as > the object argument a dummy object of type BaseClass. Since this object > argument is cv-unqualified, the calls incoherently resolve to the first > overload of baseDevice. Before r12-6075, this incorrect result would > just get silently discarded and we'd end up redoing OR at instantiation > time using 'this' as the object argument. But after r12-6075, we now > reuse this incorrect result at instantiation time. > > This patch fixes this by making finish_call_expr request from > maybe_dummy_object a cv-qualified object consistent with the cv-quals of > 'this'. That way, ahead of time OR using a dummy object will give us > the right answer and we could safely reuse it at instantiation time. > > NB: r7-755 is also the cause of the related issue PR105742. Not sure > if there's a fix that could resolve both PRs at once.. > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK > for trunk/12? > > PR c++/105637 > > gcc/cp/ChangeLog: > > * semantics.cc (finish_call_expr): Pass a cv-qualified object > type to maybe_dummy_object that is consistent with the > cv-qualifiers of 'this' if available. > > gcc/testsuite/ChangeLog: > > * g++.dg/template/non-dependent23.C: New test. > --- > gcc/cp/semantics.cc | 15 ++++++++--- > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ > 2 files changed, 37 insertions(+), 3 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index cd7a2818feb..1d9348c6cf1 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, > [class.access.base] says that we need to convert 'this' to B* as > part of the access, so we pass 'B' to maybe_dummy_object. */ > > + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)); > if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) > { > /* A constructor call always uses a dummy object. (This constructor > call which has the form A::A () is actually invalid and we are > going to reject it later in build_new_method_call.) */ > - object = build_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn))); > + object = build_dummy_object (object_type); > } > else > - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), > - NULL); > + { > + if (current_class_ref) > + { > + /* Make sure that if maybe_dummy_object gives us a dummy object, > + it'll have the same cv-quals as '*this'. */ > + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); > + object_type = cp_build_qualified_type (object_type, quals); > + } > + object = maybe_dummy_object (object_type, NULL); > + } > > result = build_new_method_call (object, fn, args, NULL_TREE, > (disallow_virtual Drat, this fix doesn't interact well with 'this'-capturing lambdas: struct BaseClass { void baseDevice(); // #1 void baseDevice() const = delete; // #2 }; template<class T> struct TopClass : T { void failsToCompile() { [this] { BaseClass::baseDevice(); }(); } }; template struct TopClass<BaseClass>; Here after the fix, we'd incorrectly select the const #2 overload at template definition time because current_class_ref is the const 'this' for the lambda rather than the non-const 'this' for TopClass.. I suppose we need something like current_nonlambda_class_type for getting at the innermost non-lambda 'this'? > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C > new file mode 100644 > index 00000000000..ef95c591b75 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > @@ -0,0 +1,25 @@ > +// PR c++/105637 > + > +struct BaseClass { > + void baseDevice(); // #1 > + void baseDevice() const; // #2 > + void baseDevice() volatile; // #3 > + void baseDevice() const volatile; // #4 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() const { > + BaseClass::baseDevice(); // should select #2, not #1 > + } > + > + void failsToCompile() volatile { > + BaseClass::baseDevice(); // should select #3, not #1 > + } > + > + void failsToCompile() const volatile { > + BaseClass::baseDevice(); // should select #4, not #1 > + } > +}; > + > +template struct TopClass<BaseClass>; > -- > 2.36.1.182.g6afdb07b7b > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-05-26 18:57 ` Patrick Palka @ 2022-05-26 20:39 ` Jason Merrill 2022-05-26 21:54 ` Patrick Palka 0 siblings, 1 reply; 15+ messages in thread From: Jason Merrill @ 2022-05-26 20:39 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches On 5/26/22 14:57, Patrick Palka wrote: > On Thu, 26 May 2022, Patrick Palka wrote: > >> Here we expect the calls to BaseClass::baseDevice resolve to the second, >> third and fourth overloads respectively in light of the cv-qualifiers >> of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the >> calls incorrectly resolve to the first overload at instantiation time. >> >> This happens because the calls to BaseClass::baseDevice are all deemed >> non-dependent (ever since r7-755-g23cb72663051cd made us ignore the >> dependentness of 'this' when considering the dependence of a non-static >> memfn call), hence we end up checking the call ahead of time, using as >> the object argument a dummy object of type BaseClass. Since this object >> argument is cv-unqualified, the calls incoherently resolve to the first >> overload of baseDevice. Before r12-6075, this incorrect result would >> just get silently discarded and we'd end up redoing OR at instantiation >> time using 'this' as the object argument. But after r12-6075, we now >> reuse this incorrect result at instantiation time. >> >> This patch fixes this by making finish_call_expr request from >> maybe_dummy_object a cv-qualified object consistent with the cv-quals of >> 'this'. That way, ahead of time OR using a dummy object will give us >> the right answer and we could safely reuse it at instantiation time. >> >> NB: r7-755 is also the cause of the related issue PR105742. Not sure >> if there's a fix that could resolve both PRs at once.. >> >> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK >> for trunk/12? >> >> PR c++/105637 >> >> gcc/cp/ChangeLog: >> >> * semantics.cc (finish_call_expr): Pass a cv-qualified object >> type to maybe_dummy_object that is consistent with the >> cv-qualifiers of 'this' if available. >> >> gcc/testsuite/ChangeLog: >> >> * g++.dg/template/non-dependent23.C: New test. >> --- >> gcc/cp/semantics.cc | 15 ++++++++--- >> .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ >> 2 files changed, 37 insertions(+), 3 deletions(-) >> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C >> >> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc >> index cd7a2818feb..1d9348c6cf1 100644 >> --- a/gcc/cp/semantics.cc >> +++ b/gcc/cp/semantics.cc >> @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual, >> [class.access.base] says that we need to convert 'this' to B* as >> part of the access, so we pass 'B' to maybe_dummy_object. */ >> >> + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)); >> if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) >> { >> /* A constructor call always uses a dummy object. (This constructor >> call which has the form A::A () is actually invalid and we are >> going to reject it later in build_new_method_call.) */ >> - object = build_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn))); >> + object = build_dummy_object (object_type); >> } >> else >> - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), >> - NULL); >> + { >> + if (current_class_ref) >> + { >> + /* Make sure that if maybe_dummy_object gives us a dummy object, >> + it'll have the same cv-quals as '*this'. */ >> + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); >> + object_type = cp_build_qualified_type (object_type, quals); >> + } >> + object = maybe_dummy_object (object_type, NULL); >> + } >> >> result = build_new_method_call (object, fn, args, NULL_TREE, >> (disallow_virtual > > Drat, this fix doesn't interact well with 'this'-capturing lambdas: > > struct BaseClass { > void baseDevice(); // #1 > void baseDevice() const = delete; // #2 > }; > > template<class T> > struct TopClass : T { > void failsToCompile() { > [this] { BaseClass::baseDevice(); }(); > } > }; > > template struct TopClass<BaseClass>; > > Here after the fix, we'd incorrectly select the const #2 overload at > template definition time because current_class_ref is the const 'this' > for the lambda rather than the non-const 'this' for TopClass.. I suppose > we need something like current_nonlambda_class_type for getting at the > innermost non-lambda 'this'? Do you want maybe_resolve_dummy (ob, false)? >> diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C >> new file mode 100644 >> index 00000000000..ef95c591b75 >> --- /dev/null >> +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C >> @@ -0,0 +1,25 @@ >> +// PR c++/105637 >> + >> +struct BaseClass { >> + void baseDevice(); // #1 >> + void baseDevice() const; // #2 >> + void baseDevice() volatile; // #3 >> + void baseDevice() const volatile; // #4 >> +}; >> + >> +template<class T> >> +struct TopClass : T { >> + void failsToCompile() const { >> + BaseClass::baseDevice(); // should select #2, not #1 >> + } >> + >> + void failsToCompile() volatile { >> + BaseClass::baseDevice(); // should select #3, not #1 >> + } >> + >> + void failsToCompile() const volatile { >> + BaseClass::baseDevice(); // should select #4, not #1 >> + } >> +}; >> + >> +template struct TopClass<BaseClass>; >> -- >> 2.36.1.182.g6afdb07b7b >> >> > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-05-26 20:39 ` Jason Merrill @ 2022-05-26 21:54 ` Patrick Palka 2022-05-27 13:57 ` Patrick Palka 0 siblings, 1 reply; 15+ messages in thread From: Patrick Palka @ 2022-05-26 21:54 UTC (permalink / raw) To: Jason Merrill; +Cc: Patrick Palka, gcc-patches On Thu, 26 May 2022, Jason Merrill wrote: > On 5/26/22 14:57, Patrick Palka wrote: > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > Here we expect the calls to BaseClass::baseDevice resolve to the second, > > > third and fourth overloads respectively in light of the cv-qualifiers > > > of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the > > > calls incorrectly resolve to the first overload at instantiation time. > > > > > > This happens because the calls to BaseClass::baseDevice are all deemed > > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore the > > > dependentness of 'this' when considering the dependence of a non-static > > > memfn call), hence we end up checking the call ahead of time, using as > > > the object argument a dummy object of type BaseClass. Since this object > > > argument is cv-unqualified, the calls incoherently resolve to the first > > > overload of baseDevice. Before r12-6075, this incorrect result would > > > just get silently discarded and we'd end up redoing OR at instantiation > > > time using 'this' as the object argument. But after r12-6075, we now > > > reuse this incorrect result at instantiation time. > > > > > > This patch fixes this by making finish_call_expr request from > > > maybe_dummy_object a cv-qualified object consistent with the cv-quals of > > > 'this'. That way, ahead of time OR using a dummy object will give us > > > the right answer and we could safely reuse it at instantiation time. > > > > > > NB: r7-755 is also the cause of the related issue PR105742. Not sure > > > if there's a fix that could resolve both PRs at once.. > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK > > > for trunk/12? > > > > > > PR c++/105637 > > > > > > gcc/cp/ChangeLog: > > > > > > * semantics.cc (finish_call_expr): Pass a cv-qualified object > > > type to maybe_dummy_object that is consistent with the > > > cv-qualifiers of 'this' if available. > > > > > > gcc/testsuite/ChangeLog: > > > > > > * g++.dg/template/non-dependent23.C: New test. > > > --- > > > gcc/cp/semantics.cc | 15 ++++++++--- > > > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ > > > 2 files changed, 37 insertions(+), 3 deletions(-) > > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > index cd7a2818feb..1d9348c6cf1 100644 > > > --- a/gcc/cp/semantics.cc > > > +++ b/gcc/cp/semantics.cc > > > @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> > > > **args, bool disallow_virtual, > > > [class.access.base] says that we need to convert 'this' to B* as > > > part of the access, so we pass 'B' to maybe_dummy_object. */ > > > + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)); > > > if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) > > > { > > > /* A constructor call always uses a dummy object. (This constructor > > > call which has the form A::A () is actually invalid and we are > > > going to reject it later in build_new_method_call.) */ > > > - object = build_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO > > > (fn))); > > > + object = build_dummy_object (object_type); > > > } > > > else > > > - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), > > > - NULL); > > > + { > > > + if (current_class_ref) > > > + { > > > + /* Make sure that if maybe_dummy_object gives us a dummy object, > > > + it'll have the same cv-quals as '*this'. */ > > > + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); > > > + object_type = cp_build_qualified_type (object_type, quals); > > > + } > > > + object = maybe_dummy_object (object_type, NULL); > > > + } > > > result = build_new_method_call (object, fn, args, NULL_TREE, > > > (disallow_virtual > > > > Drat, this fix doesn't interact well with 'this'-capturing lambdas: > > > > struct BaseClass { > > void baseDevice(); // #1 > > void baseDevice() const = delete; // #2 > > }; > > > > template<class T> > > struct TopClass : T { > > void failsToCompile() { > > [this] { BaseClass::baseDevice(); }(); > > } > > }; > > > > template struct TopClass<BaseClass>; > > > > Here after the fix, we'd incorrectly select the const #2 overload at > > template definition time because current_class_ref is the const 'this' > > for the lambda rather than the non-const 'this' for TopClass.. I suppose > > we need something like current_nonlambda_class_type for getting at the > > innermost non-lambda 'this'? > > Do you want maybe_resolve_dummy (ob, false)? That sadly doesn't seem to work -- the object type is BaseClass which is not necessarily a base of the dependent TopClass<T>, so resolvable_dummy_lambda returns NULL_TREE. I guess it would work at instantiation time though. > > > > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C > > > b/gcc/testsuite/g++.dg/template/non-dependent23.C > > > new file mode 100644 > > > index 00000000000..ef95c591b75 > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > > > @@ -0,0 +1,25 @@ > > > +// PR c++/105637 > > > + > > > +struct BaseClass { > > > + void baseDevice(); // #1 > > > + void baseDevice() const; // #2 > > > + void baseDevice() volatile; // #3 > > > + void baseDevice() const volatile; // #4 > > > +}; > > > + > > > +template<class T> > > > +struct TopClass : T { > > > + void failsToCompile() const { > > > + BaseClass::baseDevice(); // should select #2, not #1 > > > + } > > > + > > > + void failsToCompile() volatile { > > > + BaseClass::baseDevice(); // should select #3, not #1 > > > + } > > > + > > > + void failsToCompile() const volatile { > > > + BaseClass::baseDevice(); // should select #4, not #1 > > > + } > > > +}; > > > + > > > +template struct TopClass<BaseClass>; > > > -- > > > 2.36.1.182.g6afdb07b7b > > > > > > > > > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-05-26 21:54 ` Patrick Palka @ 2022-05-27 13:57 ` Patrick Palka 2022-06-02 15:57 ` Patrick Palka 2022-06-02 19:44 ` Jason Merrill 0 siblings, 2 replies; 15+ messages in thread From: Patrick Palka @ 2022-05-27 13:57 UTC (permalink / raw) To: Patrick Palka; +Cc: Jason Merrill, gcc-patches On Thu, 26 May 2022, Patrick Palka wrote: > On Thu, 26 May 2022, Jason Merrill wrote: > > > On 5/26/22 14:57, Patrick Palka wrote: > > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > > > Here we expect the calls to BaseClass::baseDevice resolve to the second, > > > > third and fourth overloads respectively in light of the cv-qualifiers > > > > of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the > > > > calls incorrectly resolve to the first overload at instantiation time. > > > > > > > > This happens because the calls to BaseClass::baseDevice are all deemed > > > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore the > > > > dependentness of 'this' when considering the dependence of a non-static > > > > memfn call), hence we end up checking the call ahead of time, using as > > > > the object argument a dummy object of type BaseClass. Since this object > > > > argument is cv-unqualified, the calls incoherently resolve to the first > > > > overload of baseDevice. Before r12-6075, this incorrect result would > > > > just get silently discarded and we'd end up redoing OR at instantiation > > > > time using 'this' as the object argument. But after r12-6075, we now > > > > reuse this incorrect result at instantiation time. > > > > > > > > This patch fixes this by making finish_call_expr request from > > > > maybe_dummy_object a cv-qualified object consistent with the cv-quals of > > > > 'this'. That way, ahead of time OR using a dummy object will give us > > > > the right answer and we could safely reuse it at instantiation time. > > > > > > > > NB: r7-755 is also the cause of the related issue PR105742. Not sure > > > > if there's a fix that could resolve both PRs at once.. > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK > > > > for trunk/12? > > > > > > > > PR c++/105637 > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > * semantics.cc (finish_call_expr): Pass a cv-qualified object > > > > type to maybe_dummy_object that is consistent with the > > > > cv-qualifiers of 'this' if available. > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > * g++.dg/template/non-dependent23.C: New test. > > > > --- > > > > gcc/cp/semantics.cc | 15 ++++++++--- > > > > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ > > > > 2 files changed, 37 insertions(+), 3 deletions(-) > > > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > > index cd7a2818feb..1d9348c6cf1 100644 > > > > --- a/gcc/cp/semantics.cc > > > > +++ b/gcc/cp/semantics.cc > > > > @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> > > > > **args, bool disallow_virtual, > > > > [class.access.base] says that we need to convert 'this' to B* as > > > > part of the access, so we pass 'B' to maybe_dummy_object. */ > > > > + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)); > > > > if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) > > > > { > > > > /* A constructor call always uses a dummy object. (This constructor > > > > call which has the form A::A () is actually invalid and we are > > > > going to reject it later in build_new_method_call.) */ > > > > - object = build_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO > > > > (fn))); > > > > + object = build_dummy_object (object_type); > > > > } > > > > else > > > > - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), > > > > - NULL); > > > > + { > > > > + if (current_class_ref) > > > > + { > > > > + /* Make sure that if maybe_dummy_object gives us a dummy object, > > > > + it'll have the same cv-quals as '*this'. */ > > > > + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); > > > > + object_type = cp_build_qualified_type (object_type, quals); > > > > + } > > > > + object = maybe_dummy_object (object_type, NULL); > > > > + } > > > > result = build_new_method_call (object, fn, args, NULL_TREE, > > > > (disallow_virtual > > > > > > Drat, this fix doesn't interact well with 'this'-capturing lambdas: > > > > > > struct BaseClass { > > > void baseDevice(); // #1 > > > void baseDevice() const = delete; // #2 > > > }; > > > > > > template<class T> > > > struct TopClass : T { > > > void failsToCompile() { > > > [this] { BaseClass::baseDevice(); }(); > > > } > > > }; > > > > > > template struct TopClass<BaseClass>; > > > > > > Here after the fix, we'd incorrectly select the const #2 overload at > > > template definition time because current_class_ref is the const 'this' > > > for the lambda rather than the non-const 'this' for TopClass.. I suppose > > > we need something like current_nonlambda_class_type for getting at the > > > innermost non-lambda 'this'? > > > > Do you want maybe_resolve_dummy (ob, false)? > > That sadly doesn't seem to work -- the object type is BaseClass which is > not necessarily a base of the dependent TopClass<T>, so > resolvable_dummy_lambda returns NULL_TREE. I guess it would work at > instantiation time though. Ah, what seems to work well is directly using lambda_expr_this_capture instead of maybe_resolve_dummy. And we might as well handle this in maybe_dummy_object for benefit of all callers. How does the following look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap and regtesting in progress. -- >8 -- Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] In non-dependent23.C below we expect the BaseClass::baseDevice calls to resolve to the second, third and fourth overloads respectively in light of the cv-qualifiers of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first overload at instantiation time. This happens because the calls to BaseClass::baseDevice are all deemed non-dependent (ever since r7-755-g23cb72663051cd made us ignore 'this' dependence when considering the dependence of a non-static memfn call), hence we end up checking the call ahead of time, using as the object argument a dummy object of type BaseClass. Since this object argument is cv-unqualified, the calls incoherently resolve to the first overload of baseDevice. Before r12-6075, this incorrect result would just get silently discarded and we'd end up redoing OR at instantiation time using 'this' as the object argument. But after r12-6075, we now reuse this incorrect result at instantiation time. This patch fixes this by making maybe_dummy_object respect the cv-quals of (the non-lambda) 'this' when returning a dummy object. Thus, ahead of time OR using a dummy object will give us the right answer that is consistent with the instantiation time answer. An earlier version of this patch didn't handle 'this'-capturing lambdas correctly, which caused us to mishandle lambda-this22.C below. PR c++/105637 gcc/cp/ChangeLog: * tree.cc (maybe_dummy_object): When returning a dummy object, respect the cv-quals of 'this' if available. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/lambda/lambda-this22.C: New test. * g++.dg/template/non-dependent23.C: New test. --- gcc/cp/tree.cc | 19 +++++++++++++- .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++++ .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 09162795801..679bf05b721 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) (TREE_TYPE (current_class_ref), context))) decl = current_class_ref; else - decl = build_dummy_object (context); + { + /* Return a dummy object whose cv-quals are consistent with (the + non-lambda) 'this' if available. */ + if (current_class_ref) + { + int quals = 0; + if (current == current_class_type) + quals = cp_type_quals (TREE_TYPE (current_class_ref)); + else if (lambda_function (current_class_type)) + { + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); + if (tree cap = lambda_expr_this_capture (lambda, false)) + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); + } + context = cp_build_qualified_type (context, quals); + } + decl = build_dummy_object (context); + } return decl; } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C new file mode 100644 index 00000000000..c9e512b1621 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C @@ -0,0 +1,20 @@ +// PR c++/105637 +// { dg-do compile { target c++11 } } + +struct BaseClass { + void baseDevice(); // #1 + void baseDevice() const = delete; // #2 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() { + [this] { BaseClass::baseDevice(); }(); // should select #2, not #1 + } + + void failsToCompile() const { + [this] { BaseClass::baseDevice(); }(); // { dg-error "deleted" } + } +}; + +template struct TopClass<BaseClass>; diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C new file mode 100644 index 00000000000..ef95c591b75 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C @@ -0,0 +1,25 @@ +// PR c++/105637 + +struct BaseClass { + void baseDevice(); // #1 + void baseDevice() const; // #2 + void baseDevice() volatile; // #3 + void baseDevice() const volatile; // #4 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() const { + BaseClass::baseDevice(); // should select #2, not #1 + } + + void failsToCompile() volatile { + BaseClass::baseDevice(); // should select #3, not #1 + } + + void failsToCompile() const volatile { + BaseClass::baseDevice(); // should select #4, not #1 + } +}; + +template struct TopClass<BaseClass>; -- 2.36.1.195.g8ddf593a25 > > > > > > > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C > > > > b/gcc/testsuite/g++.dg/template/non-dependent23.C > > > > new file mode 100644 > > > > index 00000000000..ef95c591b75 > > > > --- /dev/null > > > > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > > > > @@ -0,0 +1,25 @@ > > > > +// PR c++/105637 > > > > + > > > > +struct BaseClass { > > > > + void baseDevice(); // #1 > > > > + void baseDevice() const; // #2 > > > > + void baseDevice() volatile; // #3 > > > > + void baseDevice() const volatile; // #4 > > > > +}; > > > > + > > > > +template<class T> > > > > +struct TopClass : T { > > > > + void failsToCompile() const { > > > > + BaseClass::baseDevice(); // should select #2, not #1 > > > > + } > > > > + > > > > + void failsToCompile() volatile { > > > > + BaseClass::baseDevice(); // should select #3, not #1 > > > > + } > > > > + > > > > + void failsToCompile() const volatile { > > > > + BaseClass::baseDevice(); // should select #4, not #1 > > > > + } > > > > +}; > > > > + > > > > +template struct TopClass<BaseClass>; > > > > -- > > > > 2.36.1.182.g6afdb07b7b > > > > > > > > > > > > > > > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-05-27 13:57 ` Patrick Palka @ 2022-06-02 15:57 ` Patrick Palka 2022-06-02 19:44 ` Jason Merrill 1 sibling, 0 replies; 15+ messages in thread From: Patrick Palka @ 2022-06-02 15:57 UTC (permalink / raw) To: Patrick Palka; +Cc: Jason Merrill, gcc-patches On Fri, 27 May 2022, Patrick Palka wrote: > On Thu, 26 May 2022, Patrick Palka wrote: > > > On Thu, 26 May 2022, Jason Merrill wrote: > > > > > On 5/26/22 14:57, Patrick Palka wrote: > > > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > > > > > Here we expect the calls to BaseClass::baseDevice resolve to the second, > > > > > third and fourth overloads respectively in light of the cv-qualifiers > > > > > of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the > > > > > calls incorrectly resolve to the first overload at instantiation time. > > > > > > > > > > This happens because the calls to BaseClass::baseDevice are all deemed > > > > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore the > > > > > dependentness of 'this' when considering the dependence of a non-static > > > > > memfn call), hence we end up checking the call ahead of time, using as > > > > > the object argument a dummy object of type BaseClass. Since this object > > > > > argument is cv-unqualified, the calls incoherently resolve to the first > > > > > overload of baseDevice. Before r12-6075, this incorrect result would > > > > > just get silently discarded and we'd end up redoing OR at instantiation > > > > > time using 'this' as the object argument. But after r12-6075, we now > > > > > reuse this incorrect result at instantiation time. > > > > > > > > > > This patch fixes this by making finish_call_expr request from > > > > > maybe_dummy_object a cv-qualified object consistent with the cv-quals of > > > > > 'this'. That way, ahead of time OR using a dummy object will give us > > > > > the right answer and we could safely reuse it at instantiation time. > > > > > > > > > > NB: r7-755 is also the cause of the related issue PR105742. Not sure > > > > > if there's a fix that could resolve both PRs at once.. > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK > > > > > for trunk/12? > > > > > > > > > > PR c++/105637 > > > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > > > * semantics.cc (finish_call_expr): Pass a cv-qualified object > > > > > type to maybe_dummy_object that is consistent with the > > > > > cv-qualifiers of 'this' if available. > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > * g++.dg/template/non-dependent23.C: New test. > > > > > --- > > > > > gcc/cp/semantics.cc | 15 ++++++++--- > > > > > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ > > > > > 2 files changed, 37 insertions(+), 3 deletions(-) > > > > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > > > index cd7a2818feb..1d9348c6cf1 100644 > > > > > --- a/gcc/cp/semantics.cc > > > > > +++ b/gcc/cp/semantics.cc > > > > > @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> > > > > > **args, bool disallow_virtual, > > > > > [class.access.base] says that we need to convert 'this' to B* as > > > > > part of the access, so we pass 'B' to maybe_dummy_object. */ > > > > > + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)); > > > > > if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) > > > > > { > > > > > /* A constructor call always uses a dummy object. (This constructor > > > > > call which has the form A::A () is actually invalid and we are > > > > > going to reject it later in build_new_method_call.) */ > > > > > - object = build_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO > > > > > (fn))); > > > > > + object = build_dummy_object (object_type); > > > > > } > > > > > else > > > > > - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), > > > > > - NULL); > > > > > + { > > > > > + if (current_class_ref) > > > > > + { > > > > > + /* Make sure that if maybe_dummy_object gives us a dummy object, > > > > > + it'll have the same cv-quals as '*this'. */ > > > > > + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); > > > > > + object_type = cp_build_qualified_type (object_type, quals); > > > > > + } > > > > > + object = maybe_dummy_object (object_type, NULL); > > > > > + } > > > > > result = build_new_method_call (object, fn, args, NULL_TREE, > > > > > (disallow_virtual > > > > > > > > Drat, this fix doesn't interact well with 'this'-capturing lambdas: > > > > > > > > struct BaseClass { > > > > void baseDevice(); // #1 > > > > void baseDevice() const = delete; // #2 > > > > }; > > > > > > > > template<class T> > > > > struct TopClass : T { > > > > void failsToCompile() { > > > > [this] { BaseClass::baseDevice(); }(); > > > > } > > > > }; > > > > > > > > template struct TopClass<BaseClass>; > > > > > > > > Here after the fix, we'd incorrectly select the const #2 overload at > > > > template definition time because current_class_ref is the const 'this' > > > > for the lambda rather than the non-const 'this' for TopClass.. I suppose > > > > we need something like current_nonlambda_class_type for getting at the > > > > innermost non-lambda 'this'? > > > > > > Do you want maybe_resolve_dummy (ob, false)? > > > > That sadly doesn't seem to work -- the object type is BaseClass which is > > not necessarily a base of the dependent TopClass<T>, so > > resolvable_dummy_lambda returns NULL_TREE. I guess it would work at > > instantiation time though. > > Ah, what seems to work well is directly using lambda_expr_this_capture > instead of maybe_resolve_dummy. And we might as well handle this in > maybe_dummy_object for benefit of all callers. How does the following > look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap and > regtesting in progress. > > -- >8 -- > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] > > In non-dependent23.C below we expect the BaseClass::baseDevice calls to > resolve to the second, third and fourth overloads respectively in light > of the cv-qualifiers of 'this' in each case. But ever since > r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first > overload at instantiation time. > > This happens because the calls to BaseClass::baseDevice are all deemed > non-dependent (ever since r7-755-g23cb72663051cd made us ignore 'this' > dependence when considering the dependence of a non-static memfn call), > hence we end up checking the call ahead of time, using as the object > argument a dummy object of type BaseClass. Since this object argument > is cv-unqualified, the calls incoherently resolve to the first overload > of baseDevice. Before r12-6075, this incorrect result would just get > silently discarded and we'd end up redoing OR at instantiation time > using 'this' as the object argument. But after r12-6075, we now reuse > this incorrect result at instantiation time. > > This patch fixes this by making maybe_dummy_object respect the cv-quals > of (the non-lambda) 'this' when returning a dummy object. Thus, ahead > of time OR using a dummy object will give us the right answer that is > consistent with the instantiation time answer. > > An earlier version of this patch didn't handle 'this'-capturing lambdas > correctly, which caused us to mishandle lambda-this22.C below. Ping. > > PR c++/105637 > > gcc/cp/ChangeLog: > > * tree.cc (maybe_dummy_object): When returning a dummy > object, respect the cv-quals of 'this' if available. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > * g++.dg/template/non-dependent23.C: New test. > --- > gcc/cp/tree.cc | 19 +++++++++++++- > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++++ > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ > 3 files changed, 63 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > index 09162795801..679bf05b721 100644 > --- a/gcc/cp/tree.cc > +++ b/gcc/cp/tree.cc > @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) > (TREE_TYPE (current_class_ref), context))) > decl = current_class_ref; > else > - decl = build_dummy_object (context); > + { > + /* Return a dummy object whose cv-quals are consistent with (the > + non-lambda) 'this' if available. */ > + if (current_class_ref) > + { > + int quals = 0; > + if (current == current_class_type) > + quals = cp_type_quals (TREE_TYPE (current_class_ref)); > + else if (lambda_function (current_class_type)) > + { > + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); > + if (tree cap = lambda_expr_this_capture (lambda, false)) > + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); > + } > + context = cp_build_qualified_type (context, quals); > + } > + decl = build_dummy_object (context); > + } > > return decl; > } > diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > new file mode 100644 > index 00000000000..c9e512b1621 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > @@ -0,0 +1,20 @@ > +// PR c++/105637 > +// { dg-do compile { target c++11 } } > + > +struct BaseClass { > + void baseDevice(); // #1 > + void baseDevice() const = delete; // #2 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() { > + [this] { BaseClass::baseDevice(); }(); // should select #2, not #1 > + } > + > + void failsToCompile() const { > + [this] { BaseClass::baseDevice(); }(); // { dg-error "deleted" } > + } > +}; > + > +template struct TopClass<BaseClass>; > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C > new file mode 100644 > index 00000000000..ef95c591b75 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > @@ -0,0 +1,25 @@ > +// PR c++/105637 > + > +struct BaseClass { > + void baseDevice(); // #1 > + void baseDevice() const; // #2 > + void baseDevice() volatile; // #3 > + void baseDevice() const volatile; // #4 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() const { > + BaseClass::baseDevice(); // should select #2, not #1 > + } > + > + void failsToCompile() volatile { > + BaseClass::baseDevice(); // should select #3, not #1 > + } > + > + void failsToCompile() const volatile { > + BaseClass::baseDevice(); // should select #4, not #1 > + } > +}; > + > +template struct TopClass<BaseClass>; > -- > 2.36.1.195.g8ddf593a25 > > > > > > > > > > > > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > b/gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > new file mode 100644 > > > > > index 00000000000..ef95c591b75 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > @@ -0,0 +1,25 @@ > > > > > +// PR c++/105637 > > > > > + > > > > > +struct BaseClass { > > > > > + void baseDevice(); // #1 > > > > > + void baseDevice() const; // #2 > > > > > + void baseDevice() volatile; // #3 > > > > > + void baseDevice() const volatile; // #4 > > > > > +}; > > > > > + > > > > > +template<class T> > > > > > +struct TopClass : T { > > > > > + void failsToCompile() const { > > > > > + BaseClass::baseDevice(); // should select #2, not #1 > > > > > + } > > > > > + > > > > > + void failsToCompile() volatile { > > > > > + BaseClass::baseDevice(); // should select #3, not #1 > > > > > + } > > > > > + > > > > > + void failsToCompile() const volatile { > > > > > + BaseClass::baseDevice(); // should select #4, not #1 > > > > > + } > > > > > +}; > > > > > + > > > > > +template struct TopClass<BaseClass>; > > > > > -- > > > > > 2.36.1.182.g6afdb07b7b > > > > > > > > > > > > > > > > > > > > > > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-05-27 13:57 ` Patrick Palka 2022-06-02 15:57 ` Patrick Palka @ 2022-06-02 19:44 ` Jason Merrill 2022-06-02 19:57 ` Patrick Palka 1 sibling, 1 reply; 15+ messages in thread From: Jason Merrill @ 2022-06-02 19:44 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches On 5/27/22 09:57, Patrick Palka wrote: > On Thu, 26 May 2022, Patrick Palka wrote: > >> On Thu, 26 May 2022, Jason Merrill wrote: >> >>> On 5/26/22 14:57, Patrick Palka wrote: >>>> On Thu, 26 May 2022, Patrick Palka wrote: >>>> >>>>> Here we expect the calls to BaseClass::baseDevice resolve to the second, >>>>> third and fourth overloads respectively in light of the cv-qualifiers >>>>> of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, the >>>>> calls incorrectly resolve to the first overload at instantiation time. >>>>> >>>>> This happens because the calls to BaseClass::baseDevice are all deemed >>>>> non-dependent (ever since r7-755-g23cb72663051cd made us ignore the >>>>> dependentness of 'this' when considering the dependence of a non-static >>>>> memfn call), hence we end up checking the call ahead of time, using as >>>>> the object argument a dummy object of type BaseClass. Since this object >>>>> argument is cv-unqualified, the calls incoherently resolve to the first >>>>> overload of baseDevice. Before r12-6075, this incorrect result would >>>>> just get silently discarded and we'd end up redoing OR at instantiation >>>>> time using 'this' as the object argument. But after r12-6075, we now >>>>> reuse this incorrect result at instantiation time. >>>>> >>>>> This patch fixes this by making finish_call_expr request from >>>>> maybe_dummy_object a cv-qualified object consistent with the cv-quals of >>>>> 'this'. That way, ahead of time OR using a dummy object will give us >>>>> the right answer and we could safely reuse it at instantiation time. >>>>> >>>>> NB: r7-755 is also the cause of the related issue PR105742. Not sure >>>>> if there's a fix that could resolve both PRs at once.. >>>>> >>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK >>>>> for trunk/12? >>>>> >>>>> PR c++/105637 >>>>> >>>>> gcc/cp/ChangeLog: >>>>> >>>>> * semantics.cc (finish_call_expr): Pass a cv-qualified object >>>>> type to maybe_dummy_object that is consistent with the >>>>> cv-qualifiers of 'this' if available. >>>>> >>>>> gcc/testsuite/ChangeLog: >>>>> >>>>> * g++.dg/template/non-dependent23.C: New test. >>>>> --- >>>>> gcc/cp/semantics.cc | 15 ++++++++--- >>>>> .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ >>>>> 2 files changed, 37 insertions(+), 3 deletions(-) >>>>> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C >>>>> >>>>> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc >>>>> index cd7a2818feb..1d9348c6cf1 100644 >>>>> --- a/gcc/cp/semantics.cc >>>>> +++ b/gcc/cp/semantics.cc >>>>> @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> >>>>> **args, bool disallow_virtual, >>>>> [class.access.base] says that we need to convert 'this' to B* as >>>>> part of the access, so we pass 'B' to maybe_dummy_object. */ >>>>> + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)); >>>>> if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) >>>>> { >>>>> /* A constructor call always uses a dummy object. (This constructor >>>>> call which has the form A::A () is actually invalid and we are >>>>> going to reject it later in build_new_method_call.) */ >>>>> - object = build_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO >>>>> (fn))); >>>>> + object = build_dummy_object (object_type); >>>>> } >>>>> else >>>>> - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), >>>>> - NULL); >>>>> + { >>>>> + if (current_class_ref) >>>>> + { >>>>> + /* Make sure that if maybe_dummy_object gives us a dummy object, >>>>> + it'll have the same cv-quals as '*this'. */ >>>>> + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); >>>>> + object_type = cp_build_qualified_type (object_type, quals); >>>>> + } >>>>> + object = maybe_dummy_object (object_type, NULL); >>>>> + } >>>>> result = build_new_method_call (object, fn, args, NULL_TREE, >>>>> (disallow_virtual >>>> >>>> Drat, this fix doesn't interact well with 'this'-capturing lambdas: >>>> >>>> struct BaseClass { >>>> void baseDevice(); // #1 >>>> void baseDevice() const = delete; // #2 >>>> }; >>>> >>>> template<class T> >>>> struct TopClass : T { >>>> void failsToCompile() { >>>> [this] { BaseClass::baseDevice(); }(); >>>> } >>>> }; >>>> >>>> template struct TopClass<BaseClass>; >>>> >>>> Here after the fix, we'd incorrectly select the const #2 overload at >>>> template definition time because current_class_ref is the const 'this' >>>> for the lambda rather than the non-const 'this' for TopClass.. I suppose >>>> we need something like current_nonlambda_class_type for getting at the >>>> innermost non-lambda 'this'? >>> >>> Do you want maybe_resolve_dummy (ob, false)? >> >> That sadly doesn't seem to work -- the object type is BaseClass which is >> not necessarily a base of the dependent TopClass<T>, so >> resolvable_dummy_lambda returns NULL_TREE. I guess it would work at >> instantiation time though. > > Ah, what seems to work well is directly using lambda_expr_this_capture > instead of maybe_resolve_dummy. And we might as well handle this in > maybe_dummy_object for benefit of all callers. How does the following > look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap and > regtesting in progress. > > -- >8 -- > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] > > In non-dependent23.C below we expect the BaseClass::baseDevice calls to > resolve to the second, third and fourth overloads respectively in light > of the cv-qualifiers of 'this' in each case. But ever since > r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first > overload at instantiation time. > > This happens because the calls to BaseClass::baseDevice are all deemed > non-dependent (ever since r7-755-g23cb72663051cd made us ignore 'this' > dependence when considering the dependence of a non-static memfn call), > hence we end up checking the call ahead of time, using as the object > argument a dummy object of type BaseClass. Since this object argument > is cv-unqualified, the calls incoherently resolve to the first overload > of baseDevice. Before r12-6075, this incorrect result would just get > silently discarded and we'd end up redoing OR at instantiation time > using 'this' as the object argument. But after r12-6075, we now reuse > this incorrect result at instantiation time. > > This patch fixes this by making maybe_dummy_object respect the cv-quals > of (the non-lambda) 'this' when returning a dummy object. Thus, ahead > of time OR using a dummy object will give us the right answer that is > consistent with the instantiation time answer. > > An earlier version of this patch didn't handle 'this'-capturing lambdas > correctly, which caused us to mishandle lambda-this22.C below. > > PR c++/105637 > > gcc/cp/ChangeLog: > > * tree.cc (maybe_dummy_object): When returning a dummy > object, respect the cv-quals of 'this' if available. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > * g++.dg/template/non-dependent23.C: New test. > --- > gcc/cp/tree.cc | 19 +++++++++++++- > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++++ > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ > 3 files changed, 63 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > index 09162795801..679bf05b721 100644 > --- a/gcc/cp/tree.cc > +++ b/gcc/cp/tree.cc > @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) > (TREE_TYPE (current_class_ref), context))) > decl = current_class_ref; > else > - decl = build_dummy_object (context); > + { > + /* Return a dummy object whose cv-quals are consistent with (the > + non-lambda) 'this' if available. */ > + if (current_class_ref) > + { > + int quals = 0; > + if (current == current_class_type) > + quals = cp_type_quals (TREE_TYPE (current_class_ref)); > + else if (lambda_function (current_class_type)) > + { > + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); How about else if (tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type)) ? OK with that change. > + if (tree cap = lambda_expr_this_capture (lambda, false)) > + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); > + } > + context = cp_build_qualified_type (context, quals); > + } > + decl = build_dummy_object (context); > + } > > return decl; > } > diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > new file mode 100644 > index 00000000000..c9e512b1621 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > @@ -0,0 +1,20 @@ > +// PR c++/105637 > +// { dg-do compile { target c++11 } } > + > +struct BaseClass { > + void baseDevice(); // #1 > + void baseDevice() const = delete; // #2 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() { > + [this] { BaseClass::baseDevice(); }(); // should select #2, not #1 > + } > + > + void failsToCompile() const { > + [this] { BaseClass::baseDevice(); }(); // { dg-error "deleted" } > + } > +}; > + > +template struct TopClass<BaseClass>; > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C > new file mode 100644 > index 00000000000..ef95c591b75 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > @@ -0,0 +1,25 @@ > +// PR c++/105637 > + > +struct BaseClass { > + void baseDevice(); // #1 > + void baseDevice() const; // #2 > + void baseDevice() volatile; // #3 > + void baseDevice() const volatile; // #4 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() const { > + BaseClass::baseDevice(); // should select #2, not #1 > + } > + > + void failsToCompile() volatile { > + BaseClass::baseDevice(); // should select #3, not #1 > + } > + > + void failsToCompile() const volatile { > + BaseClass::baseDevice(); // should select #4, not #1 > + } > +}; > + > +template struct TopClass<BaseClass>; ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-02 19:44 ` Jason Merrill @ 2022-06-02 19:57 ` Patrick Palka 2022-06-02 20:30 ` Jason Merrill 0 siblings, 1 reply; 15+ messages in thread From: Patrick Palka @ 2022-06-02 19:57 UTC (permalink / raw) To: Jason Merrill; +Cc: Patrick Palka, gcc-patches On Thu, 2 Jun 2022, Jason Merrill wrote: > On 5/27/22 09:57, Patrick Palka wrote: > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > On Thu, 26 May 2022, Jason Merrill wrote: > > > > > > > On 5/26/22 14:57, Patrick Palka wrote: > > > > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > > > > > > > Here we expect the calls to BaseClass::baseDevice resolve to the > > > > > > second, > > > > > > third and fourth overloads respectively in light of the > > > > > > cv-qualifiers > > > > > > of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, > > > > > > the > > > > > > calls incorrectly resolve to the first overload at instantiation > > > > > > time. > > > > > > > > > > > > This happens because the calls to BaseClass::baseDevice are all > > > > > > deemed > > > > > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore the > > > > > > dependentness of 'this' when considering the dependence of a > > > > > > non-static > > > > > > memfn call), hence we end up checking the call ahead of time, using > > > > > > as > > > > > > the object argument a dummy object of type BaseClass. Since this > > > > > > object > > > > > > argument is cv-unqualified, the calls incoherently resolve to the > > > > > > first > > > > > > overload of baseDevice. Before r12-6075, this incorrect result > > > > > > would > > > > > > just get silently discarded and we'd end up redoing OR at > > > > > > instantiation > > > > > > time using 'this' as the object argument. But after r12-6075, we > > > > > > now > > > > > > reuse this incorrect result at instantiation time. > > > > > > > > > > > > This patch fixes this by making finish_call_expr request from > > > > > > maybe_dummy_object a cv-qualified object consistent with the > > > > > > cv-quals of > > > > > > 'this'. That way, ahead of time OR using a dummy object will give > > > > > > us > > > > > > the right answer and we could safely reuse it at instantiation time. > > > > > > > > > > > > NB: r7-755 is also the cause of the related issue PR105742. Not > > > > > > sure > > > > > > if there's a fix that could resolve both PRs at once.. > > > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK > > > > > > for trunk/12? > > > > > > > > > > > > PR c++/105637 > > > > > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > > > > > * semantics.cc (finish_call_expr): Pass a cv-qualified object > > > > > > type to maybe_dummy_object that is consistent with the > > > > > > cv-qualifiers of 'this' if available. > > > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > > > * g++.dg/template/non-dependent23.C: New test. > > > > > > --- > > > > > > gcc/cp/semantics.cc | 15 ++++++++--- > > > > > > .../g++.dg/template/non-dependent23.C | 25 > > > > > > +++++++++++++++++++ > > > > > > 2 files changed, 37 insertions(+), 3 deletions(-) > > > > > > create mode 100644 > > > > > > gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > > > > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > > > > index cd7a2818feb..1d9348c6cf1 100644 > > > > > > --- a/gcc/cp/semantics.cc > > > > > > +++ b/gcc/cp/semantics.cc > > > > > > @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> > > > > > > **args, bool disallow_virtual, > > > > > > [class.access.base] says that we need to convert 'this' to B* > > > > > > as > > > > > > part of the access, so we pass 'B' to maybe_dummy_object. */ > > > > > > + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO > > > > > > (fn)); > > > > > > if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) > > > > > > { > > > > > > /* A constructor call always uses a dummy object. (This > > > > > > constructor > > > > > > call which has the form A::A () is actually invalid and > > > > > > we are > > > > > > going to reject it later in build_new_method_call.) */ > > > > > > - object = build_dummy_object (BINFO_TYPE > > > > > > (BASELINK_ACCESS_BINFO > > > > > > (fn))); > > > > > > + object = build_dummy_object (object_type); > > > > > > } > > > > > > else > > > > > > - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO > > > > > > (fn)), > > > > > > - NULL); > > > > > > + { > > > > > > + if (current_class_ref) > > > > > > + { > > > > > > + /* Make sure that if maybe_dummy_object gives us a dummy > > > > > > object, > > > > > > + it'll have the same cv-quals as '*this'. */ > > > > > > + int quals = cp_type_quals (TREE_TYPE > > > > > > (current_class_ref)); > > > > > > + object_type = cp_build_qualified_type (object_type, > > > > > > quals); > > > > > > + } > > > > > > + object = maybe_dummy_object (object_type, NULL); > > > > > > + } > > > > > > result = build_new_method_call (object, fn, args, > > > > > > NULL_TREE, > > > > > > (disallow_virtual > > > > > > > > > > Drat, this fix doesn't interact well with 'this'-capturing lambdas: > > > > > > > > > > struct BaseClass { > > > > > void baseDevice(); // #1 > > > > > void baseDevice() const = delete; // #2 > > > > > }; > > > > > > > > > > template<class T> > > > > > struct TopClass : T { > > > > > void failsToCompile() { > > > > > [this] { BaseClass::baseDevice(); }(); > > > > > } > > > > > }; > > > > > > > > > > template struct TopClass<BaseClass>; > > > > > > > > > > Here after the fix, we'd incorrectly select the const #2 overload at > > > > > template definition time because current_class_ref is the const 'this' > > > > > for the lambda rather than the non-const 'this' for TopClass.. I > > > > > suppose > > > > > we need something like current_nonlambda_class_type for getting at the > > > > > innermost non-lambda 'this'? > > > > > > > > Do you want maybe_resolve_dummy (ob, false)? > > > > > > That sadly doesn't seem to work -- the object type is BaseClass which is > > > not necessarily a base of the dependent TopClass<T>, so > > > resolvable_dummy_lambda returns NULL_TREE. I guess it would work at > > > instantiation time though. > > > > Ah, what seems to work well is directly using lambda_expr_this_capture > > instead of maybe_resolve_dummy. And we might as well handle this in > > maybe_dummy_object for benefit of all callers. How does the following > > look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap and > > regtesting in progress. > > > > -- >8 -- > > > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call > > [PR105637] > > > > In non-dependent23.C below we expect the BaseClass::baseDevice calls to > > resolve to the second, third and fourth overloads respectively in light > > of the cv-qualifiers of 'this' in each case. But ever since > > r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first > > overload at instantiation time. > > > > This happens because the calls to BaseClass::baseDevice are all deemed > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore 'this' > > dependence when considering the dependence of a non-static memfn call), > > hence we end up checking the call ahead of time, using as the object > > argument a dummy object of type BaseClass. Since this object argument > > is cv-unqualified, the calls incoherently resolve to the first overload > > of baseDevice. Before r12-6075, this incorrect result would just get > > silently discarded and we'd end up redoing OR at instantiation time > > using 'this' as the object argument. But after r12-6075, we now reuse > > this incorrect result at instantiation time. > > > > This patch fixes this by making maybe_dummy_object respect the cv-quals > > of (the non-lambda) 'this' when returning a dummy object. Thus, ahead > > of time OR using a dummy object will give us the right answer that is > > consistent with the instantiation time answer. > > > > An earlier version of this patch didn't handle 'this'-capturing lambdas > > correctly, which caused us to mishandle lambda-this22.C below. > > > > PR c++/105637 > > > > gcc/cp/ChangeLog: > > > > * tree.cc (maybe_dummy_object): When returning a dummy > > object, respect the cv-quals of 'this' if available. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > > * g++.dg/template/non-dependent23.C: New test. > > --- > > gcc/cp/tree.cc | 19 +++++++++++++- > > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++++ > > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ > > 3 files changed, 63 insertions(+), 1 deletion(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > > index 09162795801..679bf05b721 100644 > > --- a/gcc/cp/tree.cc > > +++ b/gcc/cp/tree.cc > > @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) > > (TREE_TYPE (current_class_ref), context))) > > decl = current_class_ref; > > else > > - decl = build_dummy_object (context); > > + { > > + /* Return a dummy object whose cv-quals are consistent with (the > > + non-lambda) 'this' if available. */ > > + if (current_class_ref) > > + { > > + int quals = 0; > > + if (current == current_class_type) > > + quals = cp_type_quals (TREE_TYPE (current_class_ref)); > > + else if (lambda_function (current_class_type)) > > + { > > + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); > > How about > > else if (tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type)) > > ? OK with that change. Unfortunately the lambda_function test is necessary to avoid crashing on lambda-ice11.C; the test mirrors what resolvable_dummy_lambda does ever since r207999 / r208028 to avoid the crash. > > > > + if (tree cap = lambda_expr_this_capture (lambda, false)) > > + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); > > + } > > + context = cp_build_qualified_type (context, quals); > > + } > > + decl = build_dummy_object (context); > > + } > > return decl; > > } > > diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > > b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > > new file mode 100644 > > index 00000000000..c9e512b1621 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > > @@ -0,0 +1,20 @@ > > +// PR c++/105637 > > +// { dg-do compile { target c++11 } } > > + > > +struct BaseClass { > > + void baseDevice(); // #1 > > + void baseDevice() const = delete; // #2 > > +}; > > + > > +template<class T> > > +struct TopClass : T { > > + void failsToCompile() { > > + [this] { BaseClass::baseDevice(); }(); // should select #2, not #1 > > + } > > + > > + void failsToCompile() const { > > + [this] { BaseClass::baseDevice(); }(); // { dg-error "deleted" } > > + } > > +}; > > + > > +template struct TopClass<BaseClass>; > > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C > > b/gcc/testsuite/g++.dg/template/non-dependent23.C > > new file mode 100644 > > index 00000000000..ef95c591b75 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > > @@ -0,0 +1,25 @@ > > +// PR c++/105637 > > + > > +struct BaseClass { > > + void baseDevice(); // #1 > > + void baseDevice() const; // #2 > > + void baseDevice() volatile; // #3 > > + void baseDevice() const volatile; // #4 > > +}; > > + > > +template<class T> > > +struct TopClass : T { > > + void failsToCompile() const { > > + BaseClass::baseDevice(); // should select #2, not #1 > > + } > > + > > + void failsToCompile() volatile { > > + BaseClass::baseDevice(); // should select #3, not #1 > > + } > > + > > + void failsToCompile() const volatile { > > + BaseClass::baseDevice(); // should select #4, not #1 > > + } > > +}; > > + > > +template struct TopClass<BaseClass>; > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-02 19:57 ` Patrick Palka @ 2022-06-02 20:30 ` Jason Merrill 2022-06-03 14:46 ` Patrick Palka 0 siblings, 1 reply; 15+ messages in thread From: Jason Merrill @ 2022-06-02 20:30 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches On 6/2/22 15:57, Patrick Palka wrote: > On Thu, 2 Jun 2022, Jason Merrill wrote: > >> On 5/27/22 09:57, Patrick Palka wrote: >>> On Thu, 26 May 2022, Patrick Palka wrote: >>> >>>> On Thu, 26 May 2022, Jason Merrill wrote: >>>> >>>>> On 5/26/22 14:57, Patrick Palka wrote: >>>>>> On Thu, 26 May 2022, Patrick Palka wrote: >>>>>> >>>>>>> Here we expect the calls to BaseClass::baseDevice resolve to the >>>>>>> second, >>>>>>> third and fourth overloads respectively in light of the >>>>>>> cv-qualifiers >>>>>>> of 'this' in each case. But ever since r12-6075-g2decd2cabe5a4f, >>>>>>> the >>>>>>> calls incorrectly resolve to the first overload at instantiation >>>>>>> time. >>>>>>> >>>>>>> This happens because the calls to BaseClass::baseDevice are all >>>>>>> deemed >>>>>>> non-dependent (ever since r7-755-g23cb72663051cd made us ignore the >>>>>>> dependentness of 'this' when considering the dependence of a >>>>>>> non-static >>>>>>> memfn call), hence we end up checking the call ahead of time, using >>>>>>> as >>>>>>> the object argument a dummy object of type BaseClass. Since this >>>>>>> object >>>>>>> argument is cv-unqualified, the calls incoherently resolve to the >>>>>>> first >>>>>>> overload of baseDevice. Before r12-6075, this incorrect result >>>>>>> would >>>>>>> just get silently discarded and we'd end up redoing OR at >>>>>>> instantiation >>>>>>> time using 'this' as the object argument. But after r12-6075, we >>>>>>> now >>>>>>> reuse this incorrect result at instantiation time. >>>>>>> >>>>>>> This patch fixes this by making finish_call_expr request from >>>>>>> maybe_dummy_object a cv-qualified object consistent with the >>>>>>> cv-quals of >>>>>>> 'this'. That way, ahead of time OR using a dummy object will give >>>>>>> us >>>>>>> the right answer and we could safely reuse it at instantiation time. >>>>>>> >>>>>>> NB: r7-755 is also the cause of the related issue PR105742. Not >>>>>>> sure >>>>>>> if there's a fix that could resolve both PRs at once.. >>>>>>> >>>>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK >>>>>>> for trunk/12? >>>>>>> >>>>>>> PR c++/105637 >>>>>>> >>>>>>> gcc/cp/ChangeLog: >>>>>>> >>>>>>> * semantics.cc (finish_call_expr): Pass a cv-qualified object >>>>>>> type to maybe_dummy_object that is consistent with the >>>>>>> cv-qualifiers of 'this' if available. >>>>>>> >>>>>>> gcc/testsuite/ChangeLog: >>>>>>> >>>>>>> * g++.dg/template/non-dependent23.C: New test. >>>>>>> --- >>>>>>> gcc/cp/semantics.cc | 15 ++++++++--- >>>>>>> .../g++.dg/template/non-dependent23.C | 25 >>>>>>> +++++++++++++++++++ >>>>>>> 2 files changed, 37 insertions(+), 3 deletions(-) >>>>>>> create mode 100644 >>>>>>> gcc/testsuite/g++.dg/template/non-dependent23.C >>>>>>> >>>>>>> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc >>>>>>> index cd7a2818feb..1d9348c6cf1 100644 >>>>>>> --- a/gcc/cp/semantics.cc >>>>>>> +++ b/gcc/cp/semantics.cc >>>>>>> @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, va_gc> >>>>>>> **args, bool disallow_virtual, >>>>>>> [class.access.base] says that we need to convert 'this' to B* >>>>>>> as >>>>>>> part of the access, so we pass 'B' to maybe_dummy_object. */ >>>>>>> + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO >>>>>>> (fn)); >>>>>>> if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn (fn))) >>>>>>> { >>>>>>> /* A constructor call always uses a dummy object. (This >>>>>>> constructor >>>>>>> call which has the form A::A () is actually invalid and >>>>>>> we are >>>>>>> going to reject it later in build_new_method_call.) */ >>>>>>> - object = build_dummy_object (BINFO_TYPE >>>>>>> (BASELINK_ACCESS_BINFO >>>>>>> (fn))); >>>>>>> + object = build_dummy_object (object_type); >>>>>>> } >>>>>>> else >>>>>>> - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO >>>>>>> (fn)), >>>>>>> - NULL); >>>>>>> + { >>>>>>> + if (current_class_ref) >>>>>>> + { >>>>>>> + /* Make sure that if maybe_dummy_object gives us a dummy >>>>>>> object, >>>>>>> + it'll have the same cv-quals as '*this'. */ >>>>>>> + int quals = cp_type_quals (TREE_TYPE >>>>>>> (current_class_ref)); >>>>>>> + object_type = cp_build_qualified_type (object_type, >>>>>>> quals); >>>>>>> + } >>>>>>> + object = maybe_dummy_object (object_type, NULL); >>>>>>> + } >>>>>>> result = build_new_method_call (object, fn, args, >>>>>>> NULL_TREE, >>>>>>> (disallow_virtual >>>>>> >>>>>> Drat, this fix doesn't interact well with 'this'-capturing lambdas: >>>>>> >>>>>> struct BaseClass { >>>>>> void baseDevice(); // #1 >>>>>> void baseDevice() const = delete; // #2 >>>>>> }; >>>>>> >>>>>> template<class T> >>>>>> struct TopClass : T { >>>>>> void failsToCompile() { >>>>>> [this] { BaseClass::baseDevice(); }(); >>>>>> } >>>>>> }; >>>>>> >>>>>> template struct TopClass<BaseClass>; >>>>>> >>>>>> Here after the fix, we'd incorrectly select the const #2 overload at >>>>>> template definition time because current_class_ref is the const 'this' >>>>>> for the lambda rather than the non-const 'this' for TopClass.. I >>>>>> suppose >>>>>> we need something like current_nonlambda_class_type for getting at the >>>>>> innermost non-lambda 'this'? >>>>> >>>>> Do you want maybe_resolve_dummy (ob, false)? >>>> >>>> That sadly doesn't seem to work -- the object type is BaseClass which is >>>> not necessarily a base of the dependent TopClass<T>, so >>>> resolvable_dummy_lambda returns NULL_TREE. I guess it would work at >>>> instantiation time though. >>> >>> Ah, what seems to work well is directly using lambda_expr_this_capture >>> instead of maybe_resolve_dummy. And we might as well handle this in >>> maybe_dummy_object for benefit of all callers. How does the following >>> look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap and >>> regtesting in progress. >>> >>> -- >8 -- >>> >>> Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call >>> [PR105637] >>> >>> In non-dependent23.C below we expect the BaseClass::baseDevice calls to >>> resolve to the second, third and fourth overloads respectively in light >>> of the cv-qualifiers of 'this' in each case. But ever since >>> r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first >>> overload at instantiation time. >>> >>> This happens because the calls to BaseClass::baseDevice are all deemed >>> non-dependent (ever since r7-755-g23cb72663051cd made us ignore 'this' >>> dependence when considering the dependence of a non-static memfn call), >>> hence we end up checking the call ahead of time, using as the object >>> argument a dummy object of type BaseClass. Since this object argument >>> is cv-unqualified, the calls incoherently resolve to the first overload >>> of baseDevice. Before r12-6075, this incorrect result would just get >>> silently discarded and we'd end up redoing OR at instantiation time >>> using 'this' as the object argument. But after r12-6075, we now reuse >>> this incorrect result at instantiation time. >>> >>> This patch fixes this by making maybe_dummy_object respect the cv-quals >>> of (the non-lambda) 'this' when returning a dummy object. Thus, ahead >>> of time OR using a dummy object will give us the right answer that is >>> consistent with the instantiation time answer. >>> >>> An earlier version of this patch didn't handle 'this'-capturing lambdas >>> correctly, which caused us to mishandle lambda-this22.C below. >>> >>> PR c++/105637 >>> >>> gcc/cp/ChangeLog: >>> >>> * tree.cc (maybe_dummy_object): When returning a dummy >>> object, respect the cv-quals of 'this' if available. >>> >>> gcc/testsuite/ChangeLog: >>> >>> * g++.dg/cpp0x/lambda/lambda-this22.C: New test. >>> * g++.dg/template/non-dependent23.C: New test. >>> --- >>> gcc/cp/tree.cc | 19 +++++++++++++- >>> .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++++ >>> .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++++++ >>> 3 files changed, 63 insertions(+), 1 deletion(-) >>> create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C >>> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C >>> >>> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc >>> index 09162795801..679bf05b721 100644 >>> --- a/gcc/cp/tree.cc >>> +++ b/gcc/cp/tree.cc >>> @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) >>> (TREE_TYPE (current_class_ref), context))) >>> decl = current_class_ref; >>> else >>> - decl = build_dummy_object (context); >>> + { >>> + /* Return a dummy object whose cv-quals are consistent with (the >>> + non-lambda) 'this' if available. */ >>> + if (current_class_ref) >>> + { >>> + int quals = 0; >>> + if (current == current_class_type) >>> + quals = cp_type_quals (TREE_TYPE (current_class_ref)); >>> + else if (lambda_function (current_class_type)) >>> + { >>> + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); >> >> How about >> >> else if (tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type)) >> >> ? OK with that change. > > Unfortunately the lambda_function test is necessary to avoid crashing > on lambda-ice11.C; the test mirrors what resolvable_dummy_lambda does > ever since r207999 / r208028 to avoid the crash. Hmm, how about adjusting lambda_expr_this_capture to avoid the crash? >>> + if (tree cap = lambda_expr_this_capture (lambda, false)) >>> + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); >>> + } >>> + context = cp_build_qualified_type (context, quals); >>> + } >>> + decl = build_dummy_object (context); >>> + } >>> return decl; >>> } >>> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C >>> b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C >>> new file mode 100644 >>> index 00000000000..c9e512b1621 >>> --- /dev/null >>> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C >>> @@ -0,0 +1,20 @@ >>> +// PR c++/105637 >>> +// { dg-do compile { target c++11 } } >>> + >>> +struct BaseClass { >>> + void baseDevice(); // #1 >>> + void baseDevice() const = delete; // #2 >>> +}; >>> + >>> +template<class T> >>> +struct TopClass : T { >>> + void failsToCompile() { >>> + [this] { BaseClass::baseDevice(); }(); // should select #2, not #1 >>> + } >>> + >>> + void failsToCompile() const { >>> + [this] { BaseClass::baseDevice(); }(); // { dg-error "deleted" } >>> + } >>> +}; >>> + >>> +template struct TopClass<BaseClass>; >>> diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C >>> b/gcc/testsuite/g++.dg/template/non-dependent23.C >>> new file mode 100644 >>> index 00000000000..ef95c591b75 >>> --- /dev/null >>> +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C >>> @@ -0,0 +1,25 @@ >>> +// PR c++/105637 >>> + >>> +struct BaseClass { >>> + void baseDevice(); // #1 >>> + void baseDevice() const; // #2 >>> + void baseDevice() volatile; // #3 >>> + void baseDevice() const volatile; // #4 >>> +}; >>> + >>> +template<class T> >>> +struct TopClass : T { >>> + void failsToCompile() const { >>> + BaseClass::baseDevice(); // should select #2, not #1 >>> + } >>> + >>> + void failsToCompile() volatile { >>> + BaseClass::baseDevice(); // should select #3, not #1 >>> + } >>> + >>> + void failsToCompile() const volatile { >>> + BaseClass::baseDevice(); // should select #4, not #1 >>> + } >>> +}; >>> + >>> +template struct TopClass<BaseClass>; >> >> > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-02 20:30 ` Jason Merrill @ 2022-06-03 14:46 ` Patrick Palka 2022-06-03 14:53 ` Jason Merrill 0 siblings, 1 reply; 15+ messages in thread From: Patrick Palka @ 2022-06-03 14:46 UTC (permalink / raw) To: Jason Merrill; +Cc: Patrick Palka, gcc-patches On Thu, 2 Jun 2022, Jason Merrill wrote: > On 6/2/22 15:57, Patrick Palka wrote: > > On Thu, 2 Jun 2022, Jason Merrill wrote: > > > > > On 5/27/22 09:57, Patrick Palka wrote: > > > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > > > > > On Thu, 26 May 2022, Jason Merrill wrote: > > > > > > > > > > > On 5/26/22 14:57, Patrick Palka wrote: > > > > > > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > > > > > > > > > > > Here we expect the calls to BaseClass::baseDevice resolve to the > > > > > > > > second, > > > > > > > > third and fourth overloads respectively in light of the > > > > > > > > cv-qualifiers > > > > > > > > of 'this' in each case. But ever since > > > > > > > > r12-6075-g2decd2cabe5a4f, > > > > > > > > the > > > > > > > > calls incorrectly resolve to the first overload at instantiation > > > > > > > > time. > > > > > > > > > > > > > > > > This happens because the calls to BaseClass::baseDevice are all > > > > > > > > deemed > > > > > > > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore > > > > > > > > the > > > > > > > > dependentness of 'this' when considering the dependence of a > > > > > > > > non-static > > > > > > > > memfn call), hence we end up checking the call ahead of time, > > > > > > > > using > > > > > > > > as > > > > > > > > the object argument a dummy object of type BaseClass. Since > > > > > > > > this > > > > > > > > object > > > > > > > > argument is cv-unqualified, the calls incoherently resolve to > > > > > > > > the > > > > > > > > first > > > > > > > > overload of baseDevice. Before r12-6075, this incorrect result > > > > > > > > would > > > > > > > > just get silently discarded and we'd end up redoing OR at > > > > > > > > instantiation > > > > > > > > time using 'this' as the object argument. But after r12-6075, > > > > > > > > we > > > > > > > > now > > > > > > > > reuse this incorrect result at instantiation time. > > > > > > > > > > > > > > > > This patch fixes this by making finish_call_expr request from > > > > > > > > maybe_dummy_object a cv-qualified object consistent with the > > > > > > > > cv-quals of > > > > > > > > 'this'. That way, ahead of time OR using a dummy object will > > > > > > > > give > > > > > > > > us > > > > > > > > the right answer and we could safely reuse it at instantiation > > > > > > > > time. > > > > > > > > > > > > > > > > NB: r7-755 is also the cause of the related issue PR105742. Not > > > > > > > > sure > > > > > > > > if there's a fix that could resolve both PRs at once.. > > > > > > > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this > > > > > > > > look OK > > > > > > > > for trunk/12? > > > > > > > > > > > > > > > > PR c++/105637 > > > > > > > > > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > > > > > > > > > * semantics.cc (finish_call_expr): Pass a cv-qualified object > > > > > > > > type to maybe_dummy_object that is consistent with the > > > > > > > > cv-qualifiers of 'this' if available. > > > > > > > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > > > > > > > * g++.dg/template/non-dependent23.C: New test. > > > > > > > > --- > > > > > > > > gcc/cp/semantics.cc | 15 > > > > > > > > ++++++++--- > > > > > > > > .../g++.dg/template/non-dependent23.C | 25 > > > > > > > > +++++++++++++++++++ > > > > > > > > 2 files changed, 37 insertions(+), 3 deletions(-) > > > > > > > > create mode 100644 > > > > > > > > gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > > > > > > > > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > > > > > > index cd7a2818feb..1d9348c6cf1 100644 > > > > > > > > --- a/gcc/cp/semantics.cc > > > > > > > > +++ b/gcc/cp/semantics.cc > > > > > > > > @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, > > > > > > > > va_gc> > > > > > > > > **args, bool disallow_virtual, > > > > > > > > [class.access.base] says that we need to convert > > > > > > > > 'this' to B* > > > > > > > > as > > > > > > > > part of the access, so we pass 'B' to > > > > > > > > maybe_dummy_object. */ > > > > > > > > + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO > > > > > > > > (fn)); > > > > > > > > if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn > > > > > > > > (fn))) > > > > > > > > { > > > > > > > > /* A constructor call always uses a dummy object. > > > > > > > > (This > > > > > > > > constructor > > > > > > > > call which has the form A::A () is actually > > > > > > > > invalid and > > > > > > > > we are > > > > > > > > going to reject it later in > > > > > > > > build_new_method_call.) */ > > > > > > > > - object = build_dummy_object (BINFO_TYPE > > > > > > > > (BASELINK_ACCESS_BINFO > > > > > > > > (fn))); > > > > > > > > + object = build_dummy_object (object_type); > > > > > > > > } > > > > > > > > else > > > > > > > > - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO > > > > > > > > (fn)), > > > > > > > > - NULL); > > > > > > > > + { > > > > > > > > + if (current_class_ref) > > > > > > > > + { > > > > > > > > + /* Make sure that if maybe_dummy_object gives us a dummy > > > > > > > > object, > > > > > > > > + it'll have the same cv-quals as '*this'. */ > > > > > > > > + int quals = cp_type_quals (TREE_TYPE > > > > > > > > (current_class_ref)); > > > > > > > > + object_type = cp_build_qualified_type (object_type, > > > > > > > > quals); > > > > > > > > + } > > > > > > > > + object = maybe_dummy_object (object_type, NULL); > > > > > > > > + } > > > > > > > > result = build_new_method_call (object, fn, args, > > > > > > > > NULL_TREE, > > > > > > > > (disallow_virtual > > > > > > > > > > > > > > Drat, this fix doesn't interact well with 'this'-capturing > > > > > > > lambdas: > > > > > > > > > > > > > > struct BaseClass { > > > > > > > void baseDevice(); // #1 > > > > > > > void baseDevice() const = delete; // #2 > > > > > > > }; > > > > > > > > > > > > > > template<class T> > > > > > > > struct TopClass : T { > > > > > > > void failsToCompile() { > > > > > > > [this] { BaseClass::baseDevice(); }(); > > > > > > > } > > > > > > > }; > > > > > > > > > > > > > > template struct TopClass<BaseClass>; > > > > > > > > > > > > > > Here after the fix, we'd incorrectly select the const #2 overload > > > > > > > at > > > > > > > template definition time because current_class_ref is the const > > > > > > > 'this' > > > > > > > for the lambda rather than the non-const 'this' for TopClass.. I > > > > > > > suppose > > > > > > > we need something like current_nonlambda_class_type for getting at > > > > > > > the > > > > > > > innermost non-lambda 'this'? > > > > > > > > > > > > Do you want maybe_resolve_dummy (ob, false)? > > > > > > > > > > That sadly doesn't seem to work -- the object type is BaseClass which > > > > > is > > > > > not necessarily a base of the dependent TopClass<T>, so > > > > > resolvable_dummy_lambda returns NULL_TREE. I guess it would work at > > > > > instantiation time though. > > > > > > > > Ah, what seems to work well is directly using lambda_expr_this_capture > > > > instead of maybe_resolve_dummy. And we might as well handle this in > > > > maybe_dummy_object for benefit of all callers. How does the following > > > > look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap and > > > > regtesting in progress. > > > > > > > > -- >8 -- > > > > > > > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call > > > > [PR105637] > > > > > > > > In non-dependent23.C below we expect the BaseClass::baseDevice calls to > > > > resolve to the second, third and fourth overloads respectively in light > > > > of the cv-qualifiers of 'this' in each case. But ever since > > > > r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first > > > > overload at instantiation time. > > > > > > > > This happens because the calls to BaseClass::baseDevice are all deemed > > > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore 'this' > > > > dependence when considering the dependence of a non-static memfn call), > > > > hence we end up checking the call ahead of time, using as the object > > > > argument a dummy object of type BaseClass. Since this object argument > > > > is cv-unqualified, the calls incoherently resolve to the first overload > > > > of baseDevice. Before r12-6075, this incorrect result would just get > > > > silently discarded and we'd end up redoing OR at instantiation time > > > > using 'this' as the object argument. But after r12-6075, we now reuse > > > > this incorrect result at instantiation time. > > > > > > > > This patch fixes this by making maybe_dummy_object respect the cv-quals > > > > of (the non-lambda) 'this' when returning a dummy object. Thus, ahead > > > > of time OR using a dummy object will give us the right answer that is > > > > consistent with the instantiation time answer. > > > > > > > > An earlier version of this patch didn't handle 'this'-capturing lambdas > > > > correctly, which caused us to mishandle lambda-this22.C below. > > > > > > > > PR c++/105637 > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > * tree.cc (maybe_dummy_object): When returning a dummy > > > > object, respect the cv-quals of 'this' if available. > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > > > > * g++.dg/template/non-dependent23.C: New test. > > > > --- > > > > gcc/cp/tree.cc | 19 +++++++++++++- > > > > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++++ > > > > .../g++.dg/template/non-dependent23.C | 25 > > > > +++++++++++++++++++ > > > > 3 files changed, 63 insertions(+), 1 deletion(-) > > > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > > > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > > > > index 09162795801..679bf05b721 100644 > > > > --- a/gcc/cp/tree.cc > > > > +++ b/gcc/cp/tree.cc > > > > @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) > > > > (TREE_TYPE (current_class_ref), context))) > > > > decl = current_class_ref; > > > > else > > > > - decl = build_dummy_object (context); > > > > + { > > > > + /* Return a dummy object whose cv-quals are consistent with (the > > > > + non-lambda) 'this' if available. */ > > > > + if (current_class_ref) > > > > + { > > > > + int quals = 0; > > > > + if (current == current_class_type) > > > > + quals = cp_type_quals (TREE_TYPE (current_class_ref)); > > > > + else if (lambda_function (current_class_type)) > > > > + { > > > > + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); > > > > > > How about > > > > > > else if (tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type)) > > > > > > ? OK with that change. > > > > Unfortunately the lambda_function test is necessary to avoid crashing > > on lambda-ice11.C; the test mirrors what resolvable_dummy_lambda does > > ever since r207999 / r208028 to avoid the crash. > > Hmm, how about adjusting lambda_expr_this_capture to avoid the crash? I'm afraid I'm not sure how to do that :/ In particular for the case where add_capture_p is nonzero and the given lambda lacks a lambda_function. I suppose we can relax the assert in the !add_capture_p case but that seems somewhat hacky. I noticed that finish_this_expr, another user of lambda_expr_this_capture, isn't guarded by resolvable_dummy_lambda. I believe it gets away with this because it checks lambda-ness of TREE_TYPE (current_class_ref) instead of current_class_type. Perhaps we should do the same in maybe_dummy_object? This avoids the ICE in lambda-ice11.C without needing to check lambda_function, and seems like a cleaner approach overall. -- >8 -- Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] PR c++/105637 gcc/cp/ChangeLog: * tree.cc (maybe_dummy_object): When returning a dummy object, respect the cv-quals of 'this' if available. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/lambda/lambda-this22.C: New test. * g++.dg/template/non-dependent23.C: New test. --- gcc/cp/tree.cc | 31 ++++++++++++++----- .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 ++++++++++++ .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 2b9cb7e1c7b..183febffb5d 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -4319,15 +4319,32 @@ maybe_dummy_object (tree type, tree* binfop) if (binfop) *binfop = binfo; - if (current_class_ref - /* current_class_ref might not correspond to current_class_type if - we're in tsubst_default_argument or a lambda-declarator; in either - case, we want to use current_class_ref if it matches CONTEXT. */ - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (current_class_ref), context))) + /* current_class_ref might not correspond to current_class_type if + we're in tsubst_default_argument or a lambda-declarator; in either + case, we want to use current_class_ref if it matches CONTEXT. */ + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : NULL_TREE; + if (ctype + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) decl = current_class_ref; else - decl = build_dummy_object (context); + { + /* Return a dummy object whose cv-quals are consistent with (the + non-lambda) 'this' if available. */ + if (ctype) + { + int quals = 0; + if (LAMBDA_TYPE_P (ctype)) + { + tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype); + if (tree cap = lambda_expr_this_capture (lambda, false)) + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); + } + else + quals = cp_type_quals (ctype); + context = cp_build_qualified_type (context, quals); + } + decl = build_dummy_object (context); + } return decl; } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C new file mode 100644 index 00000000000..c9e512b1621 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C @@ -0,0 +1,20 @@ +// PR c++/105637 +// { dg-do compile { target c++11 } } + +struct BaseClass { + void baseDevice(); // #1 + void baseDevice() const = delete; // #2 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() { + [this] { BaseClass::baseDevice(); }(); // should select #2, not #1 + } + + void failsToCompile() const { + [this] { BaseClass::baseDevice(); }(); // { dg-error "deleted" } + } +}; + +template struct TopClass<BaseClass>; diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C new file mode 100644 index 00000000000..ef95c591b75 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C @@ -0,0 +1,25 @@ +// PR c++/105637 + +struct BaseClass { + void baseDevice(); // #1 + void baseDevice() const; // #2 + void baseDevice() volatile; // #3 + void baseDevice() const volatile; // #4 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() const { + BaseClass::baseDevice(); // should select #2, not #1 + } + + void failsToCompile() volatile { + BaseClass::baseDevice(); // should select #3, not #1 + } + + void failsToCompile() const volatile { + BaseClass::baseDevice(); // should select #4, not #1 + } +}; + +template struct TopClass<BaseClass>; -- 2.36.1.210.g2668e3608e ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-03 14:46 ` Patrick Palka @ 2022-06-03 14:53 ` Jason Merrill 2022-06-03 15:04 ` Patrick Palka 0 siblings, 1 reply; 15+ messages in thread From: Jason Merrill @ 2022-06-03 14:53 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches On 6/3/22 10:46, Patrick Palka wrote: > On Thu, 2 Jun 2022, Jason Merrill wrote: > >> On 6/2/22 15:57, Patrick Palka wrote: >>> On Thu, 2 Jun 2022, Jason Merrill wrote: >>> >>>> On 5/27/22 09:57, Patrick Palka wrote: >>>>> On Thu, 26 May 2022, Patrick Palka wrote: >>>>> >>>>>> On Thu, 26 May 2022, Jason Merrill wrote: >>>>>> >>>>>>> On 5/26/22 14:57, Patrick Palka wrote: >>>>>>>> On Thu, 26 May 2022, Patrick Palka wrote: >>>>>>>> >>>>>>>>> Here we expect the calls to BaseClass::baseDevice resolve to the >>>>>>>>> second, >>>>>>>>> third and fourth overloads respectively in light of the >>>>>>>>> cv-qualifiers >>>>>>>>> of 'this' in each case. But ever since >>>>>>>>> r12-6075-g2decd2cabe5a4f, >>>>>>>>> the >>>>>>>>> calls incorrectly resolve to the first overload at instantiation >>>>>>>>> time. >>>>>>>>> >>>>>>>>> This happens because the calls to BaseClass::baseDevice are all >>>>>>>>> deemed >>>>>>>>> non-dependent (ever since r7-755-g23cb72663051cd made us ignore >>>>>>>>> the >>>>>>>>> dependentness of 'this' when considering the dependence of a >>>>>>>>> non-static >>>>>>>>> memfn call), hence we end up checking the call ahead of time, >>>>>>>>> using >>>>>>>>> as >>>>>>>>> the object argument a dummy object of type BaseClass. Since >>>>>>>>> this >>>>>>>>> object >>>>>>>>> argument is cv-unqualified, the calls incoherently resolve to >>>>>>>>> the >>>>>>>>> first >>>>>>>>> overload of baseDevice. Before r12-6075, this incorrect result >>>>>>>>> would >>>>>>>>> just get silently discarded and we'd end up redoing OR at >>>>>>>>> instantiation >>>>>>>>> time using 'this' as the object argument. But after r12-6075, >>>>>>>>> we >>>>>>>>> now >>>>>>>>> reuse this incorrect result at instantiation time. >>>>>>>>> >>>>>>>>> This patch fixes this by making finish_call_expr request from >>>>>>>>> maybe_dummy_object a cv-qualified object consistent with the >>>>>>>>> cv-quals of >>>>>>>>> 'this'. That way, ahead of time OR using a dummy object will >>>>>>>>> give >>>>>>>>> us >>>>>>>>> the right answer and we could safely reuse it at instantiation >>>>>>>>> time. >>>>>>>>> >>>>>>>>> NB: r7-755 is also the cause of the related issue PR105742. Not >>>>>>>>> sure >>>>>>>>> if there's a fix that could resolve both PRs at once.. >>>>>>>>> >>>>>>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this >>>>>>>>> look OK >>>>>>>>> for trunk/12? >>>>>>>>> >>>>>>>>> PR c++/105637 >>>>>>>>> >>>>>>>>> gcc/cp/ChangeLog: >>>>>>>>> >>>>>>>>> * semantics.cc (finish_call_expr): Pass a cv-qualified object >>>>>>>>> type to maybe_dummy_object that is consistent with the >>>>>>>>> cv-qualifiers of 'this' if available. >>>>>>>>> >>>>>>>>> gcc/testsuite/ChangeLog: >>>>>>>>> >>>>>>>>> * g++.dg/template/non-dependent23.C: New test. >>>>>>>>> --- >>>>>>>>> gcc/cp/semantics.cc | 15 >>>>>>>>> ++++++++--- >>>>>>>>> .../g++.dg/template/non-dependent23.C | 25 >>>>>>>>> +++++++++++++++++++ >>>>>>>>> 2 files changed, 37 insertions(+), 3 deletions(-) >>>>>>>>> create mode 100644 >>>>>>>>> gcc/testsuite/g++.dg/template/non-dependent23.C >>>>>>>>> >>>>>>>>> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc >>>>>>>>> index cd7a2818feb..1d9348c6cf1 100644 >>>>>>>>> --- a/gcc/cp/semantics.cc >>>>>>>>> +++ b/gcc/cp/semantics.cc >>>>>>>>> @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, >>>>>>>>> va_gc> >>>>>>>>> **args, bool disallow_virtual, >>>>>>>>> [class.access.base] says that we need to convert >>>>>>>>> 'this' to B* >>>>>>>>> as >>>>>>>>> part of the access, so we pass 'B' to >>>>>>>>> maybe_dummy_object. */ >>>>>>>>> + tree object_type = BINFO_TYPE (BASELINK_ACCESS_BINFO >>>>>>>>> (fn)); >>>>>>>>> if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (get_first_fn >>>>>>>>> (fn))) >>>>>>>>> { >>>>>>>>> /* A constructor call always uses a dummy object. >>>>>>>>> (This >>>>>>>>> constructor >>>>>>>>> call which has the form A::A () is actually >>>>>>>>> invalid and >>>>>>>>> we are >>>>>>>>> going to reject it later in >>>>>>>>> build_new_method_call.) */ >>>>>>>>> - object = build_dummy_object (BINFO_TYPE >>>>>>>>> (BASELINK_ACCESS_BINFO >>>>>>>>> (fn))); >>>>>>>>> + object = build_dummy_object (object_type); >>>>>>>>> } >>>>>>>>> else >>>>>>>>> - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO >>>>>>>>> (fn)), >>>>>>>>> - NULL); >>>>>>>>> + { >>>>>>>>> + if (current_class_ref) >>>>>>>>> + { >>>>>>>>> + /* Make sure that if maybe_dummy_object gives us a dummy >>>>>>>>> object, >>>>>>>>> + it'll have the same cv-quals as '*this'. */ >>>>>>>>> + int quals = cp_type_quals (TREE_TYPE >>>>>>>>> (current_class_ref)); >>>>>>>>> + object_type = cp_build_qualified_type (object_type, >>>>>>>>> quals); >>>>>>>>> + } >>>>>>>>> + object = maybe_dummy_object (object_type, NULL); >>>>>>>>> + } >>>>>>>>> result = build_new_method_call (object, fn, args, >>>>>>>>> NULL_TREE, >>>>>>>>> (disallow_virtual >>>>>>>> >>>>>>>> Drat, this fix doesn't interact well with 'this'-capturing >>>>>>>> lambdas: >>>>>>>> >>>>>>>> struct BaseClass { >>>>>>>> void baseDevice(); // #1 >>>>>>>> void baseDevice() const = delete; // #2 >>>>>>>> }; >>>>>>>> >>>>>>>> template<class T> >>>>>>>> struct TopClass : T { >>>>>>>> void failsToCompile() { >>>>>>>> [this] { BaseClass::baseDevice(); }(); >>>>>>>> } >>>>>>>> }; >>>>>>>> >>>>>>>> template struct TopClass<BaseClass>; >>>>>>>> >>>>>>>> Here after the fix, we'd incorrectly select the const #2 overload >>>>>>>> at >>>>>>>> template definition time because current_class_ref is the const >>>>>>>> 'this' >>>>>>>> for the lambda rather than the non-const 'this' for TopClass.. I >>>>>>>> suppose >>>>>>>> we need something like current_nonlambda_class_type for getting at >>>>>>>> the >>>>>>>> innermost non-lambda 'this'? >>>>>>> >>>>>>> Do you want maybe_resolve_dummy (ob, false)? >>>>>> >>>>>> That sadly doesn't seem to work -- the object type is BaseClass which >>>>>> is >>>>>> not necessarily a base of the dependent TopClass<T>, so >>>>>> resolvable_dummy_lambda returns NULL_TREE. I guess it would work at >>>>>> instantiation time though. >>>>> >>>>> Ah, what seems to work well is directly using lambda_expr_this_capture >>>>> instead of maybe_resolve_dummy. And we might as well handle this in >>>>> maybe_dummy_object for benefit of all callers. How does the following >>>>> look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap and >>>>> regtesting in progress. >>>>> >>>>> -- >8 -- >>>>> >>>>> Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call >>>>> [PR105637] >>>>> >>>>> In non-dependent23.C below we expect the BaseClass::baseDevice calls to >>>>> resolve to the second, third and fourth overloads respectively in light >>>>> of the cv-qualifiers of 'this' in each case. But ever since >>>>> r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first >>>>> overload at instantiation time. >>>>> >>>>> This happens because the calls to BaseClass::baseDevice are all deemed >>>>> non-dependent (ever since r7-755-g23cb72663051cd made us ignore 'this' >>>>> dependence when considering the dependence of a non-static memfn call), >>>>> hence we end up checking the call ahead of time, using as the object >>>>> argument a dummy object of type BaseClass. Since this object argument >>>>> is cv-unqualified, the calls incoherently resolve to the first overload >>>>> of baseDevice. Before r12-6075, this incorrect result would just get >>>>> silently discarded and we'd end up redoing OR at instantiation time >>>>> using 'this' as the object argument. But after r12-6075, we now reuse >>>>> this incorrect result at instantiation time. >>>>> >>>>> This patch fixes this by making maybe_dummy_object respect the cv-quals >>>>> of (the non-lambda) 'this' when returning a dummy object. Thus, ahead >>>>> of time OR using a dummy object will give us the right answer that is >>>>> consistent with the instantiation time answer. >>>>> >>>>> An earlier version of this patch didn't handle 'this'-capturing lambdas >>>>> correctly, which caused us to mishandle lambda-this22.C below. >>>>> >>>>> PR c++/105637 >>>>> >>>>> gcc/cp/ChangeLog: >>>>> >>>>> * tree.cc (maybe_dummy_object): When returning a dummy >>>>> object, respect the cv-quals of 'this' if available. >>>>> >>>>> gcc/testsuite/ChangeLog: >>>>> >>>>> * g++.dg/cpp0x/lambda/lambda-this22.C: New test. >>>>> * g++.dg/template/non-dependent23.C: New test. >>>>> --- >>>>> gcc/cp/tree.cc | 19 +++++++++++++- >>>>> .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++++ >>>>> .../g++.dg/template/non-dependent23.C | 25 >>>>> +++++++++++++++++++ >>>>> 3 files changed, 63 insertions(+), 1 deletion(-) >>>>> create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C >>>>> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C >>>>> >>>>> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc >>>>> index 09162795801..679bf05b721 100644 >>>>> --- a/gcc/cp/tree.cc >>>>> +++ b/gcc/cp/tree.cc >>>>> @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) >>>>> (TREE_TYPE (current_class_ref), context))) >>>>> decl = current_class_ref; >>>>> else >>>>> - decl = build_dummy_object (context); >>>>> + { >>>>> + /* Return a dummy object whose cv-quals are consistent with (the >>>>> + non-lambda) 'this' if available. */ >>>>> + if (current_class_ref) >>>>> + { >>>>> + int quals = 0; >>>>> + if (current == current_class_type) >>>>> + quals = cp_type_quals (TREE_TYPE (current_class_ref)); >>>>> + else if (lambda_function (current_class_type)) >>>>> + { >>>>> + tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); >>>> >>>> How about >>>> >>>> else if (tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type)) >>>> >>>> ? OK with that change. >>> >>> Unfortunately the lambda_function test is necessary to avoid crashing >>> on lambda-ice11.C; the test mirrors what resolvable_dummy_lambda does >>> ever since r207999 / r208028 to avoid the crash. >> >> Hmm, how about adjusting lambda_expr_this_capture to avoid the crash? > > I'm afraid I'm not sure how to do that :/ In particular for the case > where add_capture_p is nonzero and the given lambda lacks a > lambda_function. I suppose we can relax the assert in the !add_capture_p > case but that seems somewhat hacky. > > I noticed that finish_this_expr, another user of lambda_expr_this_capture, > isn't guarded by resolvable_dummy_lambda. I believe it gets away with > this because it checks lambda-ness of TREE_TYPE (current_class_ref) instead > of current_class_type. Perhaps we should do the same in maybe_dummy_object? > This avoids the ICE in lambda-ice11.C without needing to check lambda_function, > and seems like a cleaner approach overall. > > -- >8 -- > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] > > PR c++/105637 > > gcc/cp/ChangeLog: > > * tree.cc (maybe_dummy_object): When returning a dummy > object, respect the cv-quals of 'this' if available. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > * g++.dg/template/non-dependent23.C: New test. > --- > gcc/cp/tree.cc | 31 ++++++++++++++----- > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 ++++++++++++ > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++ > 3 files changed, 69 insertions(+), 7 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > index 2b9cb7e1c7b..183febffb5d 100644 > --- a/gcc/cp/tree.cc > +++ b/gcc/cp/tree.cc > @@ -4319,15 +4319,32 @@ maybe_dummy_object (tree type, tree* binfop) > if (binfop) > *binfop = binfo; > > - if (current_class_ref > - /* current_class_ref might not correspond to current_class_type if > - we're in tsubst_default_argument or a lambda-declarator; in either > - case, we want to use current_class_ref if it matches CONTEXT. */ > - && (same_type_ignoring_top_level_qualifiers_p > - (TREE_TYPE (current_class_ref), context))) > + /* current_class_ref might not correspond to current_class_type if > + we're in tsubst_default_argument or a lambda-declarator; in either > + case, we want to use current_class_ref if it matches CONTEXT. */ > + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : NULL_TREE; > + if (ctype > + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) > decl = current_class_ref; > else > - decl = build_dummy_object (context); > + { > + /* Return a dummy object whose cv-quals are consistent with (the > + non-lambda) 'this' if available. */ > + if (ctype) > + { > + int quals = 0; > + if (LAMBDA_TYPE_P (ctype)) > + { > + tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype); And just checking CLASSTYPE_LAMBDA_EXPR (ctype) still isn't enough? > + if (tree cap = lambda_expr_this_capture (lambda, false)) > + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); > + } > + else > + quals = cp_type_quals (ctype); > + context = cp_build_qualified_type (context, quals); > + } > + decl = build_dummy_object (context); > + } > > return decl; > } > diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > new file mode 100644 > index 00000000000..c9e512b1621 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > @@ -0,0 +1,20 @@ > +// PR c++/105637 > +// { dg-do compile { target c++11 } } > + > +struct BaseClass { > + void baseDevice(); // #1 > + void baseDevice() const = delete; // #2 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() { > + [this] { BaseClass::baseDevice(); }(); // should select #2, not #1 > + } > + > + void failsToCompile() const { > + [this] { BaseClass::baseDevice(); }(); // { dg-error "deleted" } > + } > +}; > + > +template struct TopClass<BaseClass>; > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C > new file mode 100644 > index 00000000000..ef95c591b75 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > @@ -0,0 +1,25 @@ > +// PR c++/105637 > + > +struct BaseClass { > + void baseDevice(); // #1 > + void baseDevice() const; // #2 > + void baseDevice() volatile; // #3 > + void baseDevice() const volatile; // #4 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() const { > + BaseClass::baseDevice(); // should select #2, not #1 > + } > + > + void failsToCompile() volatile { > + BaseClass::baseDevice(); // should select #3, not #1 > + } > + > + void failsToCompile() const volatile { > + BaseClass::baseDevice(); // should select #4, not #1 > + } > +}; > + > +template struct TopClass<BaseClass>; ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-03 14:53 ` Jason Merrill @ 2022-06-03 15:04 ` Patrick Palka 2022-06-03 15:16 ` Jason Merrill 0 siblings, 1 reply; 15+ messages in thread From: Patrick Palka @ 2022-06-03 15:04 UTC (permalink / raw) To: Jason Merrill; +Cc: Patrick Palka, gcc-patches On Fri, 3 Jun 2022, Jason Merrill wrote: > On 6/3/22 10:46, Patrick Palka wrote: > > On Thu, 2 Jun 2022, Jason Merrill wrote: > > > > > On 6/2/22 15:57, Patrick Palka wrote: > > > > On Thu, 2 Jun 2022, Jason Merrill wrote: > > > > > > > > > On 5/27/22 09:57, Patrick Palka wrote: > > > > > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > > > > > > > > > On Thu, 26 May 2022, Jason Merrill wrote: > > > > > > > > > > > > > > > On 5/26/22 14:57, Patrick Palka wrote: > > > > > > > > > On Thu, 26 May 2022, Patrick Palka wrote: > > > > > > > > > > > > > > > > > > > Here we expect the calls to BaseClass::baseDevice resolve to > > > > > > > > > > the > > > > > > > > > > second, > > > > > > > > > > third and fourth overloads respectively in light of the > > > > > > > > > > cv-qualifiers > > > > > > > > > > of 'this' in each case. But ever since > > > > > > > > > > r12-6075-g2decd2cabe5a4f, > > > > > > > > > > the > > > > > > > > > > calls incorrectly resolve to the first overload at > > > > > > > > > > instantiation > > > > > > > > > > time. > > > > > > > > > > > > > > > > > > > > This happens because the calls to BaseClass::baseDevice are > > > > > > > > > > all > > > > > > > > > > deemed > > > > > > > > > > non-dependent (ever since r7-755-g23cb72663051cd made us > > > > > > > > > > ignore > > > > > > > > > > the > > > > > > > > > > dependentness of 'this' when considering the dependence of a > > > > > > > > > > non-static > > > > > > > > > > memfn call), hence we end up checking the call ahead of > > > > > > > > > > time, > > > > > > > > > > using > > > > > > > > > > as > > > > > > > > > > the object argument a dummy object of type BaseClass. Since > > > > > > > > > > this > > > > > > > > > > object > > > > > > > > > > argument is cv-unqualified, the calls incoherently resolve > > > > > > > > > > to > > > > > > > > > > the > > > > > > > > > > first > > > > > > > > > > overload of baseDevice. Before r12-6075, this incorrect > > > > > > > > > > result > > > > > > > > > > would > > > > > > > > > > just get silently discarded and we'd end up redoing OR at > > > > > > > > > > instantiation > > > > > > > > > > time using 'this' as the object argument. But after > > > > > > > > > > r12-6075, > > > > > > > > > > we > > > > > > > > > > now > > > > > > > > > > reuse this incorrect result at instantiation time. > > > > > > > > > > > > > > > > > > > > This patch fixes this by making finish_call_expr request > > > > > > > > > > from > > > > > > > > > > maybe_dummy_object a cv-qualified object consistent with the > > > > > > > > > > cv-quals of > > > > > > > > > > 'this'. That way, ahead of time OR using a dummy object > > > > > > > > > > will > > > > > > > > > > give > > > > > > > > > > us > > > > > > > > > > the right answer and we could safely reuse it at > > > > > > > > > > instantiation > > > > > > > > > > time. > > > > > > > > > > > > > > > > > > > > NB: r7-755 is also the cause of the related issue PR105742. > > > > > > > > > > Not > > > > > > > > > > sure > > > > > > > > > > if there's a fix that could resolve both PRs at once.. > > > > > > > > > > > > > > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this > > > > > > > > > > look OK > > > > > > > > > > for trunk/12? > > > > > > > > > > > > > > > > > > > > PR c++/105637 > > > > > > > > > > > > > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > > > > > > > > > > > > > * semantics.cc (finish_call_expr): Pass a cv-qualified > > > > > > > > > > object > > > > > > > > > > type to maybe_dummy_object that is consistent with the > > > > > > > > > > cv-qualifiers of 'this' if available. > > > > > > > > > > > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > > > > > > > > > > > * g++.dg/template/non-dependent23.C: New test. > > > > > > > > > > --- > > > > > > > > > > gcc/cp/semantics.cc | 15 > > > > > > > > > > ++++++++--- > > > > > > > > > > .../g++.dg/template/non-dependent23.C | 25 > > > > > > > > > > +++++++++++++++++++ > > > > > > > > > > 2 files changed, 37 insertions(+), 3 deletions(-) > > > > > > > > > > create mode 100644 > > > > > > > > > > gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > > > > > > > > > > > > > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > > > > > > > > > > index cd7a2818feb..1d9348c6cf1 100644 > > > > > > > > > > --- a/gcc/cp/semantics.cc > > > > > > > > > > +++ b/gcc/cp/semantics.cc > > > > > > > > > > @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, > > > > > > > > > > va_gc> > > > > > > > > > > **args, bool disallow_virtual, > > > > > > > > > > [class.access.base] says that we need to convert > > > > > > > > > > 'this' to B* > > > > > > > > > > as > > > > > > > > > > part of the access, so we pass 'B' to > > > > > > > > > > maybe_dummy_object. */ > > > > > > > > > > + tree object_type = BINFO_TYPE > > > > > > > > > > (BASELINK_ACCESS_BINFO > > > > > > > > > > (fn)); > > > > > > > > > > if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P > > > > > > > > > > (get_first_fn > > > > > > > > > > (fn))) > > > > > > > > > > { > > > > > > > > > > /* A constructor call always uses a dummy object. > > > > > > > > > > (This > > > > > > > > > > constructor > > > > > > > > > > call which has the form A::A () is actually > > > > > > > > > > invalid and > > > > > > > > > > we are > > > > > > > > > > going to reject it later in > > > > > > > > > > build_new_method_call.) */ > > > > > > > > > > - object = build_dummy_object (BINFO_TYPE > > > > > > > > > > (BASELINK_ACCESS_BINFO > > > > > > > > > > (fn))); > > > > > > > > > > + object = build_dummy_object (object_type); > > > > > > > > > > } > > > > > > > > > > else > > > > > > > > > > - object = maybe_dummy_object (BINFO_TYPE > > > > > > > > > > (BASELINK_ACCESS_BINFO > > > > > > > > > > (fn)), > > > > > > > > > > - NULL); > > > > > > > > > > + { > > > > > > > > > > + if (current_class_ref) > > > > > > > > > > + { > > > > > > > > > > + /* Make sure that if maybe_dummy_object gives us > > > > > > > > > > a dummy > > > > > > > > > > object, > > > > > > > > > > + it'll have the same cv-quals as '*this'. */ > > > > > > > > > > + int quals = cp_type_quals (TREE_TYPE > > > > > > > > > > (current_class_ref)); > > > > > > > > > > + object_type = cp_build_qualified_type > > > > > > > > > > (object_type, > > > > > > > > > > quals); > > > > > > > > > > + } > > > > > > > > > > + object = maybe_dummy_object (object_type, NULL); > > > > > > > > > > + } > > > > > > > > > > result = build_new_method_call (object, fn, > > > > > > > > > > args, > > > > > > > > > > NULL_TREE, > > > > > > > > > > (disallow_virtual > > > > > > > > > > > > > > > > > > Drat, this fix doesn't interact well with 'this'-capturing > > > > > > > > > lambdas: > > > > > > > > > > > > > > > > > > struct BaseClass { > > > > > > > > > void baseDevice(); // #1 > > > > > > > > > void baseDevice() const = delete; // #2 > > > > > > > > > }; > > > > > > > > > > > > > > > > > > template<class T> > > > > > > > > > struct TopClass : T { > > > > > > > > > void failsToCompile() { > > > > > > > > > [this] { BaseClass::baseDevice(); }(); > > > > > > > > > } > > > > > > > > > }; > > > > > > > > > > > > > > > > > > template struct TopClass<BaseClass>; > > > > > > > > > > > > > > > > > > Here after the fix, we'd incorrectly select the const #2 > > > > > > > > > overload > > > > > > > > > at > > > > > > > > > template definition time because current_class_ref is the > > > > > > > > > const > > > > > > > > > 'this' > > > > > > > > > for the lambda rather than the non-const 'this' for TopClass.. > > > > > > > > > I > > > > > > > > > suppose > > > > > > > > > we need something like current_nonlambda_class_type for > > > > > > > > > getting at > > > > > > > > > the > > > > > > > > > innermost non-lambda 'this'? > > > > > > > > > > > > > > > > Do you want maybe_resolve_dummy (ob, false)? > > > > > > > > > > > > > > That sadly doesn't seem to work -- the object type is BaseClass > > > > > > > which > > > > > > > is > > > > > > > not necessarily a base of the dependent TopClass<T>, so > > > > > > > resolvable_dummy_lambda returns NULL_TREE. I guess it would work > > > > > > > at > > > > > > > instantiation time though. > > > > > > > > > > > > Ah, what seems to work well is directly using > > > > > > lambda_expr_this_capture > > > > > > instead of maybe_resolve_dummy. And we might as well handle this in > > > > > > maybe_dummy_object for benefit of all callers. How does the > > > > > > following > > > > > > look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap > > > > > > and > > > > > > regtesting in progress. > > > > > > > > > > > > -- >8 -- > > > > > > > > > > > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call > > > > > > [PR105637] > > > > > > > > > > > > In non-dependent23.C below we expect the BaseClass::baseDevice calls > > > > > > to > > > > > > resolve to the second, third and fourth overloads respectively in > > > > > > light > > > > > > of the cv-qualifiers of 'this' in each case. But ever since > > > > > > r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first > > > > > > overload at instantiation time. > > > > > > > > > > > > This happens because the calls to BaseClass::baseDevice are all > > > > > > deemed > > > > > > non-dependent (ever since r7-755-g23cb72663051cd made us ignore > > > > > > 'this' > > > > > > dependence when considering the dependence of a non-static memfn > > > > > > call), > > > > > > hence we end up checking the call ahead of time, using as the object > > > > > > argument a dummy object of type BaseClass. Since this object > > > > > > argument > > > > > > is cv-unqualified, the calls incoherently resolve to the first > > > > > > overload > > > > > > of baseDevice. Before r12-6075, this incorrect result would just > > > > > > get > > > > > > silently discarded and we'd end up redoing OR at instantiation time > > > > > > using 'this' as the object argument. But after r12-6075, we now > > > > > > reuse > > > > > > this incorrect result at instantiation time. > > > > > > > > > > > > This patch fixes this by making maybe_dummy_object respect the > > > > > > cv-quals > > > > > > of (the non-lambda) 'this' when returning a dummy object. Thus, > > > > > > ahead > > > > > > of time OR using a dummy object will give us the right answer that > > > > > > is > > > > > > consistent with the instantiation time answer. > > > > > > > > > > > > An earlier version of this patch didn't handle 'this'-capturing > > > > > > lambdas > > > > > > correctly, which caused us to mishandle lambda-this22.C below. > > > > > > > > > > > > PR c++/105637 > > > > > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > > > > > * tree.cc (maybe_dummy_object): When returning a dummy > > > > > > object, respect the cv-quals of 'this' if available. > > > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > > > > > > * g++.dg/template/non-dependent23.C: New test. > > > > > > --- > > > > > > gcc/cp/tree.cc | 19 > > > > > > +++++++++++++- > > > > > > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 > > > > > > +++++++++++++++ > > > > > > .../g++.dg/template/non-dependent23.C | 25 > > > > > > +++++++++++++++++++ > > > > > > 3 files changed, 63 insertions(+), 1 deletion(-) > > > > > > create mode 100644 > > > > > > gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > > > > > > create mode 100644 > > > > > > gcc/testsuite/g++.dg/template/non-dependent23.C > > > > > > > > > > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > > > > > > index 09162795801..679bf05b721 100644 > > > > > > --- a/gcc/cp/tree.cc > > > > > > +++ b/gcc/cp/tree.cc > > > > > > @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) > > > > > > (TREE_TYPE (current_class_ref), context))) > > > > > > decl = current_class_ref; > > > > > > else > > > > > > - decl = build_dummy_object (context); > > > > > > + { > > > > > > + /* Return a dummy object whose cv-quals are consistent with > > > > > > (the > > > > > > + non-lambda) 'this' if available. */ > > > > > > + if (current_class_ref) > > > > > > + { > > > > > > + int quals = 0; > > > > > > + if (current == current_class_type) > > > > > > + quals = cp_type_quals (TREE_TYPE (current_class_ref)); > > > > > > + else if (lambda_function (current_class_type)) > > > > > > + { > > > > > > + tree lambda = CLASSTYPE_LAMBDA_EXPR > > > > > > (current_class_type); > > > > > > > > > > How about > > > > > > > > > > else if (tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type)) > > > > > > > > > > ? OK with that change. > > > > > > > > Unfortunately the lambda_function test is necessary to avoid crashing > > > > on lambda-ice11.C; the test mirrors what resolvable_dummy_lambda does > > > > ever since r207999 / r208028 to avoid the crash. > > > > > > Hmm, how about adjusting lambda_expr_this_capture to avoid the crash? > > > > I'm afraid I'm not sure how to do that :/ In particular for the case > > where add_capture_p is nonzero and the given lambda lacks a > > lambda_function. I suppose we can relax the assert in the !add_capture_p > > case but that seems somewhat hacky. > > > > I noticed that finish_this_expr, another user of lambda_expr_this_capture, > > isn't guarded by resolvable_dummy_lambda. I believe it gets away with > > this because it checks lambda-ness of TREE_TYPE (current_class_ref) instead > > of current_class_type. Perhaps we should do the same in maybe_dummy_object? > > This avoids the ICE in lambda-ice11.C without needing to check > > lambda_function, > > and seems like a cleaner approach overall. > > > > -- >8 -- > > > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call > > [PR105637] > > > > PR c++/105637 > > > > gcc/cp/ChangeLog: > > > > * tree.cc (maybe_dummy_object): When returning a dummy > > object, respect the cv-quals of 'this' if available. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > > * g++.dg/template/non-dependent23.C: New test. > > --- > > gcc/cp/tree.cc | 31 ++++++++++++++----- > > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 ++++++++++++ > > .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++ > > 3 files changed, 69 insertions(+), 7 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > > index 2b9cb7e1c7b..183febffb5d 100644 > > --- a/gcc/cp/tree.cc > > +++ b/gcc/cp/tree.cc > > @@ -4319,15 +4319,32 @@ maybe_dummy_object (tree type, tree* binfop) > > if (binfop) > > *binfop = binfo; > > - if (current_class_ref > > - /* current_class_ref might not correspond to current_class_type if > > - we're in tsubst_default_argument or a lambda-declarator; in either > > - case, we want to use current_class_ref if it matches CONTEXT. */ > > - && (same_type_ignoring_top_level_qualifiers_p > > - (TREE_TYPE (current_class_ref), context))) > > + /* current_class_ref might not correspond to current_class_type if > > + we're in tsubst_default_argument or a lambda-declarator; in either > > + case, we want to use current_class_ref if it matches CONTEXT. */ > > + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : > > NULL_TREE; > > + if (ctype > > + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) > > decl = current_class_ref; > > else > > - decl = build_dummy_object (context); > > + { > > + /* Return a dummy object whose cv-quals are consistent with (the > > + non-lambda) 'this' if available. */ > > + if (ctype) > > + { > > + int quals = 0; > > + if (LAMBDA_TYPE_P (ctype)) > > + { > > + tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype); > > And just checking CLASSTYPE_LAMBDA_EXPR (ctype) still isn't enough? Whoops, it appears to be enough now. I was under the mistaken impression that CLASSTYPE_LAMBDA_EXPR is only usable for LAMBDA_TYPE_P types. So like so (full bootstrap/testing in progress): -- >8 -- Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] PR c++/105637 gcc/cp/ChangeLog: * tree.cc (maybe_dummy_object): When returning a dummy object, respect the cv-quals of 'this' if available. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/lambda/lambda-this22.C: New test. * g++.dg/template/non-dependent23.C: New test. --- gcc/cp/tree.cc | 30 ++++++++++++++----- .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++ .../g++.dg/template/non-dependent23.C | 25 ++++++++++++++++ 3 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 2b9cb7e1c7b..fa9c472efac 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -4319,15 +4319,31 @@ maybe_dummy_object (tree type, tree* binfop) if (binfop) *binfop = binfo; - if (current_class_ref - /* current_class_ref might not correspond to current_class_type if - we're in tsubst_default_argument or a lambda-declarator; in either - case, we want to use current_class_ref if it matches CONTEXT. */ - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (current_class_ref), context))) + /* current_class_ref might not correspond to current_class_type if + we're in tsubst_default_argument or a lambda-declarator; in either + case, we want to use current_class_ref if it matches CONTEXT. */ + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : NULL_TREE; + if (ctype + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) decl = current_class_ref; else - decl = build_dummy_object (context); + { + /* Return a dummy object whose cv-quals are consistent with (the + non-lambda) 'this' if available. */ + if (ctype) + { + int quals = 0; + if (tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype)) + { + if (tree cap = lambda_expr_this_capture (lambda, false)) + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); + } + else + quals = cp_type_quals (ctype); + context = cp_build_qualified_type (context, quals); + } + decl = build_dummy_object (context); + } return decl; } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C new file mode 100644 index 00000000000..8c6afe06cac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C @@ -0,0 +1,20 @@ +// PR c++/105637 +// { dg-do compile { target c++11 } } + +struct Base { + void foo(); // #1 + void foo() const = delete; // #2 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() { + [this] { Base::foo(); }(); // should select #2, not #1 + } + + void failsToCompile() const { + [this] { Base::foo(); }(); // { dg-error "deleted" } + } +}; + +template struct TopClass<Base>; diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C new file mode 100644 index 00000000000..885a641a655 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C @@ -0,0 +1,25 @@ +// PR c++/105637 + +struct Base { + void foo(); // #1 + void foo() const; // #2 + void foo() volatile; // #3 + void foo() const volatile; // #4 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() const { + Base::foo(); // should select #2, not #1 + } + + void failsToCompile() volatile { + Base::foo(); // should select #3, not #1 + } + + void failsToCompile() const volatile { + Base::foo(); // should select #4, not #1 + } +}; + +template struct TopClass<Base>; -- 2.36.1.210.g2668e3608e ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-03 15:04 ` Patrick Palka @ 2022-06-03 15:16 ` Jason Merrill 2022-06-03 15:22 ` Marek Polacek 0 siblings, 1 reply; 15+ messages in thread From: Jason Merrill @ 2022-06-03 15:16 UTC (permalink / raw) To: Patrick Palka; +Cc: gcc-patches On 6/3/22 11:04, Patrick Palka wrote: > On Fri, 3 Jun 2022, Jason Merrill wrote: > >> On 6/3/22 10:46, Patrick Palka wrote: >>> On Thu, 2 Jun 2022, Jason Merrill wrote: >>> >>>> On 6/2/22 15:57, Patrick Palka wrote: >>>>> On Thu, 2 Jun 2022, Jason Merrill wrote: >>>>> >>>>>> On 5/27/22 09:57, Patrick Palka wrote: >>>>>>> On Thu, 26 May 2022, Patrick Palka wrote: >>>>>>> >>>>>>>> On Thu, 26 May 2022, Jason Merrill wrote: >>>>>>>> >>>>>>>>> On 5/26/22 14:57, Patrick Palka wrote: >>>>>>>>>> On Thu, 26 May 2022, Patrick Palka wrote: >>>>>>>>>> >>>>>>>>>>> Here we expect the calls to BaseClass::baseDevice resolve to >>>>>>>>>>> the >>>>>>>>>>> second, >>>>>>>>>>> third and fourth overloads respectively in light of the >>>>>>>>>>> cv-qualifiers >>>>>>>>>>> of 'this' in each case. But ever since >>>>>>>>>>> r12-6075-g2decd2cabe5a4f, >>>>>>>>>>> the >>>>>>>>>>> calls incorrectly resolve to the first overload at >>>>>>>>>>> instantiation >>>>>>>>>>> time. >>>>>>>>>>> >>>>>>>>>>> This happens because the calls to BaseClass::baseDevice are >>>>>>>>>>> all >>>>>>>>>>> deemed >>>>>>>>>>> non-dependent (ever since r7-755-g23cb72663051cd made us >>>>>>>>>>> ignore >>>>>>>>>>> the >>>>>>>>>>> dependentness of 'this' when considering the dependence of a >>>>>>>>>>> non-static >>>>>>>>>>> memfn call), hence we end up checking the call ahead of >>>>>>>>>>> time, >>>>>>>>>>> using >>>>>>>>>>> as >>>>>>>>>>> the object argument a dummy object of type BaseClass. Since >>>>>>>>>>> this >>>>>>>>>>> object >>>>>>>>>>> argument is cv-unqualified, the calls incoherently resolve >>>>>>>>>>> to >>>>>>>>>>> the >>>>>>>>>>> first >>>>>>>>>>> overload of baseDevice. Before r12-6075, this incorrect >>>>>>>>>>> result >>>>>>>>>>> would >>>>>>>>>>> just get silently discarded and we'd end up redoing OR at >>>>>>>>>>> instantiation >>>>>>>>>>> time using 'this' as the object argument. But after >>>>>>>>>>> r12-6075, >>>>>>>>>>> we >>>>>>>>>>> now >>>>>>>>>>> reuse this incorrect result at instantiation time. >>>>>>>>>>> >>>>>>>>>>> This patch fixes this by making finish_call_expr request >>>>>>>>>>> from >>>>>>>>>>> maybe_dummy_object a cv-qualified object consistent with the >>>>>>>>>>> cv-quals of >>>>>>>>>>> 'this'. That way, ahead of time OR using a dummy object >>>>>>>>>>> will >>>>>>>>>>> give >>>>>>>>>>> us >>>>>>>>>>> the right answer and we could safely reuse it at >>>>>>>>>>> instantiation >>>>>>>>>>> time. >>>>>>>>>>> >>>>>>>>>>> NB: r7-755 is also the cause of the related issue PR105742. >>>>>>>>>>> Not >>>>>>>>>>> sure >>>>>>>>>>> if there's a fix that could resolve both PRs at once.. >>>>>>>>>>> >>>>>>>>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this >>>>>>>>>>> look OK >>>>>>>>>>> for trunk/12? >>>>>>>>>>> >>>>>>>>>>> PR c++/105637 >>>>>>>>>>> >>>>>>>>>>> gcc/cp/ChangeLog: >>>>>>>>>>> >>>>>>>>>>> * semantics.cc (finish_call_expr): Pass a cv-qualified >>>>>>>>>>> object >>>>>>>>>>> type to maybe_dummy_object that is consistent with the >>>>>>>>>>> cv-qualifiers of 'this' if available. >>>>>>>>>>> >>>>>>>>>>> gcc/testsuite/ChangeLog: >>>>>>>>>>> >>>>>>>>>>> * g++.dg/template/non-dependent23.C: New test. >>>>>>>>>>> --- >>>>>>>>>>> gcc/cp/semantics.cc | 15 >>>>>>>>>>> ++++++++--- >>>>>>>>>>> .../g++.dg/template/non-dependent23.C | 25 >>>>>>>>>>> +++++++++++++++++++ >>>>>>>>>>> 2 files changed, 37 insertions(+), 3 deletions(-) >>>>>>>>>>> create mode 100644 >>>>>>>>>>> gcc/testsuite/g++.dg/template/non-dependent23.C >>>>>>>>>>> >>>>>>>>>>> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc >>>>>>>>>>> index cd7a2818feb..1d9348c6cf1 100644 >>>>>>>>>>> --- a/gcc/cp/semantics.cc >>>>>>>>>>> +++ b/gcc/cp/semantics.cc >>>>>>>>>>> @@ -2802,16 +2802,25 @@ finish_call_expr (tree fn, vec<tree, >>>>>>>>>>> va_gc> >>>>>>>>>>> **args, bool disallow_virtual, >>>>>>>>>>> [class.access.base] says that we need to convert >>>>>>>>>>> 'this' to B* >>>>>>>>>>> as >>>>>>>>>>> part of the access, so we pass 'B' to >>>>>>>>>>> maybe_dummy_object. */ >>>>>>>>>>> + tree object_type = BINFO_TYPE >>>>>>>>>>> (BASELINK_ACCESS_BINFO >>>>>>>>>>> (fn)); >>>>>>>>>>> if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P >>>>>>>>>>> (get_first_fn >>>>>>>>>>> (fn))) >>>>>>>>>>> { >>>>>>>>>>> /* A constructor call always uses a dummy object. >>>>>>>>>>> (This >>>>>>>>>>> constructor >>>>>>>>>>> call which has the form A::A () is actually >>>>>>>>>>> invalid and >>>>>>>>>>> we are >>>>>>>>>>> going to reject it later in >>>>>>>>>>> build_new_method_call.) */ >>>>>>>>>>> - object = build_dummy_object (BINFO_TYPE >>>>>>>>>>> (BASELINK_ACCESS_BINFO >>>>>>>>>>> (fn))); >>>>>>>>>>> + object = build_dummy_object (object_type); >>>>>>>>>>> } >>>>>>>>>>> else >>>>>>>>>>> - object = maybe_dummy_object (BINFO_TYPE >>>>>>>>>>> (BASELINK_ACCESS_BINFO >>>>>>>>>>> (fn)), >>>>>>>>>>> - NULL); >>>>>>>>>>> + { >>>>>>>>>>> + if (current_class_ref) >>>>>>>>>>> + { >>>>>>>>>>> + /* Make sure that if maybe_dummy_object gives us >>>>>>>>>>> a dummy >>>>>>>>>>> object, >>>>>>>>>>> + it'll have the same cv-quals as '*this'. */ >>>>>>>>>>> + int quals = cp_type_quals (TREE_TYPE >>>>>>>>>>> (current_class_ref)); >>>>>>>>>>> + object_type = cp_build_qualified_type >>>>>>>>>>> (object_type, >>>>>>>>>>> quals); >>>>>>>>>>> + } >>>>>>>>>>> + object = maybe_dummy_object (object_type, NULL); >>>>>>>>>>> + } >>>>>>>>>>> result = build_new_method_call (object, fn, >>>>>>>>>>> args, >>>>>>>>>>> NULL_TREE, >>>>>>>>>>> (disallow_virtual >>>>>>>>>> >>>>>>>>>> Drat, this fix doesn't interact well with 'this'-capturing >>>>>>>>>> lambdas: >>>>>>>>>> >>>>>>>>>> struct BaseClass { >>>>>>>>>> void baseDevice(); // #1 >>>>>>>>>> void baseDevice() const = delete; // #2 >>>>>>>>>> }; >>>>>>>>>> >>>>>>>>>> template<class T> >>>>>>>>>> struct TopClass : T { >>>>>>>>>> void failsToCompile() { >>>>>>>>>> [this] { BaseClass::baseDevice(); }(); >>>>>>>>>> } >>>>>>>>>> }; >>>>>>>>>> >>>>>>>>>> template struct TopClass<BaseClass>; >>>>>>>>>> >>>>>>>>>> Here after the fix, we'd incorrectly select the const #2 >>>>>>>>>> overload >>>>>>>>>> at >>>>>>>>>> template definition time because current_class_ref is the >>>>>>>>>> const >>>>>>>>>> 'this' >>>>>>>>>> for the lambda rather than the non-const 'this' for TopClass.. >>>>>>>>>> I >>>>>>>>>> suppose >>>>>>>>>> we need something like current_nonlambda_class_type for >>>>>>>>>> getting at >>>>>>>>>> the >>>>>>>>>> innermost non-lambda 'this'? >>>>>>>>> >>>>>>>>> Do you want maybe_resolve_dummy (ob, false)? >>>>>>>> >>>>>>>> That sadly doesn't seem to work -- the object type is BaseClass >>>>>>>> which >>>>>>>> is >>>>>>>> not necessarily a base of the dependent TopClass<T>, so >>>>>>>> resolvable_dummy_lambda returns NULL_TREE. I guess it would work >>>>>>>> at >>>>>>>> instantiation time though. >>>>>>> >>>>>>> Ah, what seems to work well is directly using >>>>>>> lambda_expr_this_capture >>>>>>> instead of maybe_resolve_dummy. And we might as well handle this in >>>>>>> maybe_dummy_object for benefit of all callers. How does the >>>>>>> following >>>>>>> look? Smoke tested with RUNTESTFLAGS="dg.exp=*.C", full bootstrap >>>>>>> and >>>>>>> regtesting in progress. >>>>>>> >>>>>>> -- >8 -- >>>>>>> >>>>>>> Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call >>>>>>> [PR105637] >>>>>>> >>>>>>> In non-dependent23.C below we expect the BaseClass::baseDevice calls >>>>>>> to >>>>>>> resolve to the second, third and fourth overloads respectively in >>>>>>> light >>>>>>> of the cv-qualifiers of 'this' in each case. But ever since >>>>>>> r12-6075-g2decd2cabe5a4f, the calls incorrectly resolve to the first >>>>>>> overload at instantiation time. >>>>>>> >>>>>>> This happens because the calls to BaseClass::baseDevice are all >>>>>>> deemed >>>>>>> non-dependent (ever since r7-755-g23cb72663051cd made us ignore >>>>>>> 'this' >>>>>>> dependence when considering the dependence of a non-static memfn >>>>>>> call), >>>>>>> hence we end up checking the call ahead of time, using as the object >>>>>>> argument a dummy object of type BaseClass. Since this object >>>>>>> argument >>>>>>> is cv-unqualified, the calls incoherently resolve to the first >>>>>>> overload >>>>>>> of baseDevice. Before r12-6075, this incorrect result would just >>>>>>> get >>>>>>> silently discarded and we'd end up redoing OR at instantiation time >>>>>>> using 'this' as the object argument. But after r12-6075, we now >>>>>>> reuse >>>>>>> this incorrect result at instantiation time. >>>>>>> >>>>>>> This patch fixes this by making maybe_dummy_object respect the >>>>>>> cv-quals >>>>>>> of (the non-lambda) 'this' when returning a dummy object. Thus, >>>>>>> ahead >>>>>>> of time OR using a dummy object will give us the right answer that >>>>>>> is >>>>>>> consistent with the instantiation time answer. >>>>>>> >>>>>>> An earlier version of this patch didn't handle 'this'-capturing >>>>>>> lambdas >>>>>>> correctly, which caused us to mishandle lambda-this22.C below. >>>>>>> >>>>>>> PR c++/105637 >>>>>>> >>>>>>> gcc/cp/ChangeLog: >>>>>>> >>>>>>> * tree.cc (maybe_dummy_object): When returning a dummy >>>>>>> object, respect the cv-quals of 'this' if available. >>>>>>> >>>>>>> gcc/testsuite/ChangeLog: >>>>>>> >>>>>>> * g++.dg/cpp0x/lambda/lambda-this22.C: New test. >>>>>>> * g++.dg/template/non-dependent23.C: New test. >>>>>>> --- >>>>>>> gcc/cp/tree.cc | 19 >>>>>>> +++++++++++++- >>>>>>> .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 >>>>>>> +++++++++++++++ >>>>>>> .../g++.dg/template/non-dependent23.C | 25 >>>>>>> +++++++++++++++++++ >>>>>>> 3 files changed, 63 insertions(+), 1 deletion(-) >>>>>>> create mode 100644 >>>>>>> gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C >>>>>>> create mode 100644 >>>>>>> gcc/testsuite/g++.dg/template/non-dependent23.C >>>>>>> >>>>>>> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc >>>>>>> index 09162795801..679bf05b721 100644 >>>>>>> --- a/gcc/cp/tree.cc >>>>>>> +++ b/gcc/cp/tree.cc >>>>>>> @@ -4330,7 +4330,24 @@ maybe_dummy_object (tree type, tree* binfop) >>>>>>> (TREE_TYPE (current_class_ref), context))) >>>>>>> decl = current_class_ref; >>>>>>> else >>>>>>> - decl = build_dummy_object (context); >>>>>>> + { >>>>>>> + /* Return a dummy object whose cv-quals are consistent with >>>>>>> (the >>>>>>> + non-lambda) 'this' if available. */ >>>>>>> + if (current_class_ref) >>>>>>> + { >>>>>>> + int quals = 0; >>>>>>> + if (current == current_class_type) >>>>>>> + quals = cp_type_quals (TREE_TYPE (current_class_ref)); >>>>>>> + else if (lambda_function (current_class_type)) >>>>>>> + { >>>>>>> + tree lambda = CLASSTYPE_LAMBDA_EXPR >>>>>>> (current_class_type); >>>>>> >>>>>> How about >>>>>> >>>>>> else if (tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type)) >>>>>> >>>>>> ? OK with that change. >>>>> >>>>> Unfortunately the lambda_function test is necessary to avoid crashing >>>>> on lambda-ice11.C; the test mirrors what resolvable_dummy_lambda does >>>>> ever since r207999 / r208028 to avoid the crash. >>>> >>>> Hmm, how about adjusting lambda_expr_this_capture to avoid the crash? >>> >>> I'm afraid I'm not sure how to do that :/ In particular for the case >>> where add_capture_p is nonzero and the given lambda lacks a >>> lambda_function. I suppose we can relax the assert in the !add_capture_p >>> case but that seems somewhat hacky. >>> >>> I noticed that finish_this_expr, another user of lambda_expr_this_capture, >>> isn't guarded by resolvable_dummy_lambda. I believe it gets away with >>> this because it checks lambda-ness of TREE_TYPE (current_class_ref) instead >>> of current_class_type. Perhaps we should do the same in maybe_dummy_object? >>> This avoids the ICE in lambda-ice11.C without needing to check >>> lambda_function, >>> and seems like a cleaner approach overall. >>> >>> -- >8 -- >>> >>> Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call >>> [PR105637] >>> >>> PR c++/105637 >>> >>> gcc/cp/ChangeLog: >>> >>> * tree.cc (maybe_dummy_object): When returning a dummy >>> object, respect the cv-quals of 'this' if available. >>> >>> gcc/testsuite/ChangeLog: >>> >>> * g++.dg/cpp0x/lambda/lambda-this22.C: New test. >>> * g++.dg/template/non-dependent23.C: New test. >>> --- >>> gcc/cp/tree.cc | 31 ++++++++++++++----- >>> .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 ++++++++++++ >>> .../g++.dg/template/non-dependent23.C | 25 +++++++++++++++ >>> 3 files changed, 69 insertions(+), 7 deletions(-) >>> create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C >>> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C >>> >>> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc >>> index 2b9cb7e1c7b..183febffb5d 100644 >>> --- a/gcc/cp/tree.cc >>> +++ b/gcc/cp/tree.cc >>> @@ -4319,15 +4319,32 @@ maybe_dummy_object (tree type, tree* binfop) >>> if (binfop) >>> *binfop = binfo; >>> - if (current_class_ref >>> - /* current_class_ref might not correspond to current_class_type if >>> - we're in tsubst_default_argument or a lambda-declarator; in either >>> - case, we want to use current_class_ref if it matches CONTEXT. */ >>> - && (same_type_ignoring_top_level_qualifiers_p >>> - (TREE_TYPE (current_class_ref), context))) >>> + /* current_class_ref might not correspond to current_class_type if >>> + we're in tsubst_default_argument or a lambda-declarator; in either >>> + case, we want to use current_class_ref if it matches CONTEXT. */ >>> + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : >>> NULL_TREE; >>> + if (ctype >>> + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) >>> decl = current_class_ref; >>> else >>> - decl = build_dummy_object (context); >>> + { >>> + /* Return a dummy object whose cv-quals are consistent with (the >>> + non-lambda) 'this' if available. */ >>> + if (ctype) >>> + { >>> + int quals = 0; >>> + if (LAMBDA_TYPE_P (ctype)) >>> + { >>> + tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype); >> >> And just checking CLASSTYPE_LAMBDA_EXPR (ctype) still isn't enough? > > Whoops, it appears to be enough now. I was under the mistaken > impression that CLASSTYPE_LAMBDA_EXPR is only usable for LAMBDA_TYPE_P > types. So like so (full bootstrap/testing in progress): OK. > -- >8 -- > > Subject: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] > > PR c++/105637 > > gcc/cp/ChangeLog: > > * tree.cc (maybe_dummy_object): When returning a dummy > object, respect the cv-quals of 'this' if available. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/lambda/lambda-this22.C: New test. > * g++.dg/template/non-dependent23.C: New test. > --- > gcc/cp/tree.cc | 30 ++++++++++++++----- > .../g++.dg/cpp0x/lambda/lambda-this22.C | 20 +++++++++++++ > .../g++.dg/template/non-dependent23.C | 25 ++++++++++++++++ > 3 files changed, 68 insertions(+), 7 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent23.C > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc > index 2b9cb7e1c7b..fa9c472efac 100644 > --- a/gcc/cp/tree.cc > +++ b/gcc/cp/tree.cc > @@ -4319,15 +4319,31 @@ maybe_dummy_object (tree type, tree* binfop) > if (binfop) > *binfop = binfo; > > - if (current_class_ref > - /* current_class_ref might not correspond to current_class_type if > - we're in tsubst_default_argument or a lambda-declarator; in either > - case, we want to use current_class_ref if it matches CONTEXT. */ > - && (same_type_ignoring_top_level_qualifiers_p > - (TREE_TYPE (current_class_ref), context))) > + /* current_class_ref might not correspond to current_class_type if > + we're in tsubst_default_argument or a lambda-declarator; in either > + case, we want to use current_class_ref if it matches CONTEXT. */ > + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : NULL_TREE; > + if (ctype > + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) > decl = current_class_ref; > else > - decl = build_dummy_object (context); > + { > + /* Return a dummy object whose cv-quals are consistent with (the > + non-lambda) 'this' if available. */ > + if (ctype) > + { > + int quals = 0; > + if (tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype)) > + { > + if (tree cap = lambda_expr_this_capture (lambda, false)) > + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); > + } > + else > + quals = cp_type_quals (ctype); > + context = cp_build_qualified_type (context, quals); > + } > + decl = build_dummy_object (context); > + } > > return decl; > } > diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > new file mode 100644 > index 00000000000..8c6afe06cac > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C > @@ -0,0 +1,20 @@ > +// PR c++/105637 > +// { dg-do compile { target c++11 } } > + > +struct Base { > + void foo(); // #1 > + void foo() const = delete; // #2 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() { > + [this] { Base::foo(); }(); // should select #2, not #1 > + } > + > + void failsToCompile() const { > + [this] { Base::foo(); }(); // { dg-error "deleted" } > + } > +}; > + > +template struct TopClass<Base>; > diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C > new file mode 100644 > index 00000000000..885a641a655 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C > @@ -0,0 +1,25 @@ > +// PR c++/105637 > + > +struct Base { > + void foo(); // #1 > + void foo() const; // #2 > + void foo() volatile; // #3 > + void foo() const volatile; // #4 > +}; > + > +template<class T> > +struct TopClass : T { > + void failsToCompile() const { > + Base::foo(); // should select #2, not #1 > + } > + > + void failsToCompile() volatile { > + Base::foo(); // should select #3, not #1 > + } > + > + void failsToCompile() const volatile { > + Base::foo(); // should select #4, not #1 > + } > +}; > + > +template struct TopClass<Base>; ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-03 15:16 ` Jason Merrill @ 2022-06-03 15:22 ` Marek Polacek 2022-06-03 16:04 ` Patrick Palka 0 siblings, 1 reply; 15+ messages in thread From: Marek Polacek @ 2022-06-03 15:22 UTC (permalink / raw) To: Jason Merrill; +Cc: Patrick Palka, gcc-patches On Fri, Jun 03, 2022 at 11:16:26AM -0400, Jason Merrill via Gcc-patches wrote: > On 6/3/22 11:04, Patrick Palka wrote: > > > > @@ -4319,15 +4319,32 @@ maybe_dummy_object (tree type, tree* binfop) > > > > if (binfop) > > > > *binfop = binfo; > > > > - if (current_class_ref > > > > - /* current_class_ref might not correspond to current_class_type if > > > > - we're in tsubst_default_argument or a lambda-declarator; in either > > > > - case, we want to use current_class_ref if it matches CONTEXT. */ > > > > - && (same_type_ignoring_top_level_qualifiers_p > > > > - (TREE_TYPE (current_class_ref), context))) > > > > + /* current_class_ref might not correspond to current_class_type if > > > > + we're in tsubst_default_argument or a lambda-declarator; in either > > > > + case, we want to use current_class_ref if it matches CONTEXT. */ > > > > + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : > > > > NULL_TREE; > > > > + if (ctype > > > > + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) > > > > decl = current_class_ref; > > > > else > > > > - decl = build_dummy_object (context); > > > > + { > > > > + /* Return a dummy object whose cv-quals are consistent with (the > > > > + non-lambda) 'this' if available. */ > > > > + if (ctype) > > > > + { > > > > + int quals = 0; Sorry to nitpick, but this 0 could be TYPE_UNQUALIFIED. Marek ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] 2022-06-03 15:22 ` Marek Polacek @ 2022-06-03 16:04 ` Patrick Palka 0 siblings, 0 replies; 15+ messages in thread From: Patrick Palka @ 2022-06-03 16:04 UTC (permalink / raw) To: Marek Polacek; +Cc: Jason Merrill, Patrick Palka, gcc-patches On Fri, 3 Jun 2022, Marek Polacek wrote: > On Fri, Jun 03, 2022 at 11:16:26AM -0400, Jason Merrill via Gcc-patches wrote: > > On 6/3/22 11:04, Patrick Palka wrote: > > > > > @@ -4319,15 +4319,32 @@ maybe_dummy_object (tree type, tree* binfop) > > > > > if (binfop) > > > > > *binfop = binfo; > > > > > - if (current_class_ref > > > > > - /* current_class_ref might not correspond to current_class_type if > > > > > - we're in tsubst_default_argument or a lambda-declarator; in either > > > > > - case, we want to use current_class_ref if it matches CONTEXT. */ > > > > > - && (same_type_ignoring_top_level_qualifiers_p > > > > > - (TREE_TYPE (current_class_ref), context))) > > > > > + /* current_class_ref might not correspond to current_class_type if > > > > > + we're in tsubst_default_argument or a lambda-declarator; in either > > > > > + case, we want to use current_class_ref if it matches CONTEXT. */ > > > > > + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : > > > > > NULL_TREE; > > > > > + if (ctype > > > > > + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) > > > > > decl = current_class_ref; > > > > > else > > > > > - decl = build_dummy_object (context); > > > > > + { > > > > > + /* Return a dummy object whose cv-quals are consistent with (the > > > > > + non-lambda) 'this' if available. */ > > > > > + if (ctype) > > > > > + { > > > > > + int quals = 0; > > Sorry to nitpick, but this 0 could be TYPE_UNQUALIFIED. Good point, fixed. > > Marek > > ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2022-06-03 16:04 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-05-26 18:34 [PATCH] c++: cv-quals of dummy obj for non-dep memfn call [PR105637] Patrick Palka 2022-05-26 18:57 ` Patrick Palka 2022-05-26 20:39 ` Jason Merrill 2022-05-26 21:54 ` Patrick Palka 2022-05-27 13:57 ` Patrick Palka 2022-06-02 15:57 ` Patrick Palka 2022-06-02 19:44 ` Jason Merrill 2022-06-02 19:57 ` Patrick Palka 2022-06-02 20:30 ` Jason Merrill 2022-06-03 14:46 ` Patrick Palka 2022-06-03 14:53 ` Jason Merrill 2022-06-03 15:04 ` Patrick Palka 2022-06-03 15:16 ` Jason Merrill 2022-06-03 15:22 ` Marek Polacek 2022-06-03 16:04 ` Patrick Palka
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).