[v2] c++: Fix template deduction for conversion operators with xobj parameters [PR113629]
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Testing passed
|
Commit Message
On Tue, Mar 05, 2024 at 06:19:07PM -0500, Jason Merrill wrote:
> On 3/5/24 17:47, Nathaniel Shead wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> >
> > -- >8 --
> >
> > Unification for conversion operators (DEDUCE_CONV) doesn't perform
> > transformations like handling forwarding references. This is correct in
> > general, but not for xobj parameters, which should be handled "normally"
> > for the purposes of deduction: [temp.deduct.conv] only applies to the
> > return type of the conversion function.
> >
> > PR c++/113629
> >
> > gcc/cp/ChangeLog:
> >
> > * pt.cc (type_unification_real): Use DEDUCE_CALL for xobj
> > parameters of conversion functions.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/cpp23/explicit-obj-conv-op.C: New test.
> >
> > Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> > ---
> > gcc/cp/pt.cc | 15 +++++-
> > .../g++.dg/cpp23/explicit-obj-conv-op.C | 49 +++++++++++++++++++
> > 2 files changed, 63 insertions(+), 1 deletion(-)
> > create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
> >
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index c4bc54a8fdb..632437d3424 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -23281,6 +23281,10 @@ type_unification_real (tree tparms,
> > in TARGS. */
> > NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs) = NULL_TREE;
> > + bool is_xobj_conv_fn
> > + = (strict == DEDUCE_CONV
> > + && DECL_XOBJ_MEMBER_FUNCTION_P (TREE_TYPE (tparms)));
> > +
> > again:
> > parms = xparms;
> > args = xargs;
> > @@ -23312,10 +23316,17 @@ type_unification_real (tree tparms,
> > parameter pack is a non-deduced context. */
> > continue;
> > + /* For explicit object parameters, unification should behave like
> > + normal function calls, even for conversion functions. This
> > + corresponds to the second (that is, last) argument. */
> > + unification_kind_t kind = strict;
> > + if (is_xobj_conv_fn && ia > 0)
>
> Is it necessary to check the xobj flag? Or can this just be
>
> if (strict == DEDUCE_CONV && ia > 0)
>
> ?
>
> Jason
>
I restricted it to xobj to be conservative, but I think you're right
that it's not necessary: there's nothing special about xobj here apart
from this being a new circumstance where we might actually need to unify
the object parameter.
Here's a new version of the patch. Bootstrapped and regtested (so far
only dg.exp) on x86_64-pc-linux-gnu, OK for trunk if full regtest
completes successfully?
-- >8 --
Unification for conversion operators (DEDUCE_CONV) doesn't perform
transformations like handling forwarding references. This is correct in
general, but not for xobj parameters, which should be handled "normally"
for the purposes of deduction: [temp.deduct.conv] only applies to the
return type of the conversion function.
PR c++/113629
gcc/cp/ChangeLog:
* pt.cc (type_unification_real): Only use DEDUCE_CONV for the
return type of a conversion function.
gcc/testsuite/ChangeLog:
* g++.dg/cpp23/explicit-obj-conv-op.C: New test.
Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
gcc/cp/pt.cc | 12 ++++-
.../g++.dg/cpp23/explicit-obj-conv-op.C | 49 +++++++++++++++++++
2 files changed, 60 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
Comments
On 3/5/24 22:46, Nathaniel Shead wrote:
> On Tue, Mar 05, 2024 at 06:19:07PM -0500, Jason Merrill wrote:
>> On 3/5/24 17:47, Nathaniel Shead wrote:
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
>>>
>>> -- >8 --
>>>
>>> Unification for conversion operators (DEDUCE_CONV) doesn't perform
>>> transformations like handling forwarding references. This is correct in
>>> general, but not for xobj parameters, which should be handled "normally"
>>> for the purposes of deduction: [temp.deduct.conv] only applies to the
>>> return type of the conversion function.
>>>
>>> PR c++/113629
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> * pt.cc (type_unification_real): Use DEDUCE_CALL for xobj
>>> parameters of conversion functions.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * g++.dg/cpp23/explicit-obj-conv-op.C: New test.
>>>
>>> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
>>> ---
>>> gcc/cp/pt.cc | 15 +++++-
>>> .../g++.dg/cpp23/explicit-obj-conv-op.C | 49 +++++++++++++++++++
>>> 2 files changed, 63 insertions(+), 1 deletion(-)
>>> create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
>>>
>>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
>>> index c4bc54a8fdb..632437d3424 100644
>>> --- a/gcc/cp/pt.cc
>>> +++ b/gcc/cp/pt.cc
>>> @@ -23281,6 +23281,10 @@ type_unification_real (tree tparms,
>>> in TARGS. */
>>> NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs) = NULL_TREE;
>>> + bool is_xobj_conv_fn
>>> + = (strict == DEDUCE_CONV
>>> + && DECL_XOBJ_MEMBER_FUNCTION_P (TREE_TYPE (tparms)));
>>> +
>>> again:
>>> parms = xparms;
>>> args = xargs;
>>> @@ -23312,10 +23316,17 @@ type_unification_real (tree tparms,
>>> parameter pack is a non-deduced context. */
>>> continue;
>>> + /* For explicit object parameters, unification should behave like
>>> + normal function calls, even for conversion functions. This
>>> + corresponds to the second (that is, last) argument. */
>>> + unification_kind_t kind = strict;
>>> + if (is_xobj_conv_fn && ia > 0)
>>
>> Is it necessary to check the xobj flag? Or can this just be
>>
>> if (strict == DEDUCE_CONV && ia > 0)
>>
>> ?
>>
>> Jason
>>
>
> I restricted it to xobj to be conservative, but I think you're right
> that it's not necessary: there's nothing special about xobj here apart
> from this being a new circumstance where we might actually need to unify
> the object parameter.
>
> Here's a new version of the patch. Bootstrapped and regtested (so far
> only dg.exp) on x86_64-pc-linux-gnu, OK for trunk if full regtest
> completes successfully?
OK.
> -- >8 --
>
> Unification for conversion operators (DEDUCE_CONV) doesn't perform
> transformations like handling forwarding references. This is correct in
> general, but not for xobj parameters, which should be handled "normally"
> for the purposes of deduction: [temp.deduct.conv] only applies to the
> return type of the conversion function.
>
> PR c++/113629
>
> gcc/cp/ChangeLog:
>
> * pt.cc (type_unification_real): Only use DEDUCE_CONV for the
> return type of a conversion function.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp23/explicit-obj-conv-op.C: New test.
>
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
> gcc/cp/pt.cc | 12 ++++-
> .../g++.dg/cpp23/explicit-obj-conv-op.C | 49 +++++++++++++++++++
> 2 files changed, 60 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index c4bc54a8fdb..a6e6c804130 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -23312,10 +23312,18 @@ type_unification_real (tree tparms,
> parameter pack is a non-deduced context. */
> continue;
>
> + /* [temp.deduct.conv] only applies to the deduction of the return
> + type, which is always the first argument here. Other arguments
> + (notably, explicit object parameters) should undergo normal
> + call-like unification. */
> + unification_kind_t kind = strict;
> + if (strict == DEDUCE_CONV && ia > 0)
> + kind = DEDUCE_CALL;
> +
> arg = args[ia];
> ++ia;
>
> - if (unify_one_argument (tparms, full_targs, parm, arg, subr, strict,
> + if (unify_one_argument (tparms, full_targs, parm, arg, subr, kind,
> explain_p))
> return 1;
> }
> @@ -23324,6 +23332,8 @@ type_unification_real (tree tparms,
> && parms != void_list_node
> && TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
> {
> + gcc_assert (strict != DEDUCE_CONV);
> +
> /* Unify the remaining arguments with the pack expansion type. */
> tree argvec;
> tree parmvec = make_tree_vec (1);
> diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
> new file mode 100644
> index 00000000000..a6ae4ea1dda
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
> @@ -0,0 +1,49 @@
> +// PR c++/113629
> +// { dg-do compile { target c++23 } }
> +
> +template <typename T> constexpr bool is_lvalue = false;
> +template <typename T> constexpr bool is_lvalue<T&> = true;
> +
> +struct A {
> + constexpr operator bool(this auto&& self) {
> + return is_lvalue<decltype(self)>;
> + }
> +};
> +
> +constexpr A a;
> +static_assert(static_cast<bool>(a));
> +static_assert((bool)a);
> +static_assert(!static_cast<bool>(A{}));
> +static_assert(!(bool)A{});
> +
> +struct B : A {};
> +
> +constexpr B b;
> +static_assert(static_cast<bool>(b));
> +static_assert((bool)b);
> +static_assert(!static_cast<bool>(B{}));
> +static_assert(!(bool)B{});
> +
> +struct C {
> + template <typename R, typename T>
> + explicit constexpr operator R(this T&&) {
> + return is_lvalue<T>;
> + }
> +};
> +
> +constexpr C c;
> +static_assert(static_cast<bool>(c));
> +static_assert((bool)c);
> +static_assert(!static_cast<bool>(C{}));
> +static_assert(!(bool)C{});
> +
> +struct D {
> + explicit constexpr operator bool(this const D&) { return true; }
> + explicit constexpr operator bool(this const D&&) { return false; }
> +};
> +
> +constexpr D d;
> +static_assert(static_cast<bool>(d));
> +static_assert((bool)d);
> +static_assert(!static_cast<bool>(D{}));
> +static_assert(!(bool)D{});
@@ -23312,10 +23312,18 @@ type_unification_real (tree tparms,
parameter pack is a non-deduced context. */
continue;
+ /* [temp.deduct.conv] only applies to the deduction of the return
+ type, which is always the first argument here. Other arguments
+ (notably, explicit object parameters) should undergo normal
+ call-like unification. */
+ unification_kind_t kind = strict;
+ if (strict == DEDUCE_CONV && ia > 0)
+ kind = DEDUCE_CALL;
+
arg = args[ia];
++ia;
- if (unify_one_argument (tparms, full_targs, parm, arg, subr, strict,
+ if (unify_one_argument (tparms, full_targs, parm, arg, subr, kind,
explain_p))
return 1;
}
@@ -23324,6 +23332,8 @@ type_unification_real (tree tparms,
&& parms != void_list_node
&& TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
{
+ gcc_assert (strict != DEDUCE_CONV);
+
/* Unify the remaining arguments with the pack expansion type. */
tree argvec;
tree parmvec = make_tree_vec (1);
new file mode 100644
@@ -0,0 +1,49 @@
+// PR c++/113629
+// { dg-do compile { target c++23 } }
+
+template <typename T> constexpr bool is_lvalue = false;
+template <typename T> constexpr bool is_lvalue<T&> = true;
+
+struct A {
+ constexpr operator bool(this auto&& self) {
+ return is_lvalue<decltype(self)>;
+ }
+};
+
+constexpr A a;
+static_assert(static_cast<bool>(a));
+static_assert((bool)a);
+static_assert(!static_cast<bool>(A{}));
+static_assert(!(bool)A{});
+
+struct B : A {};
+
+constexpr B b;
+static_assert(static_cast<bool>(b));
+static_assert((bool)b);
+static_assert(!static_cast<bool>(B{}));
+static_assert(!(bool)B{});
+
+struct C {
+ template <typename R, typename T>
+ explicit constexpr operator R(this T&&) {
+ return is_lvalue<T>;
+ }
+};
+
+constexpr C c;
+static_assert(static_cast<bool>(c));
+static_assert((bool)c);
+static_assert(!static_cast<bool>(C{}));
+static_assert(!(bool)C{});
+
+struct D {
+ explicit constexpr operator bool(this const D&) { return true; }
+ explicit constexpr operator bool(this const D&&) { return false; }
+};
+
+constexpr D d;
+static_assert(static_cast<bool>(d));
+static_assert((bool)d);
+static_assert(!static_cast<bool>(D{}));
+static_assert(!(bool)D{});