[PATCH RFA (libstdc++)] c++: partial ordering of object parameter [PR53499]
Jonathan Wakely
jwakely@redhat.com
Wed Dec 6 08:38:06 GMT 2023
On Wed, 6 Dec 2023 at 02:21, Jason Merrill wrote:
>
> Tested x86_64-pc-linux-gnu. Are the library test changes OK?
Sure, they seem fine.
> A reduced
> example of the issue is at https://godbolt.org/z/cPxrcnKjG
>
> -- 8< --
>
> Looks like we implemented option 1 (skip the object parameter) for CWG532
> before the issue was resolved, and never updated to the final resolution of
> option 2 (model it as a reference). More recently CWG2445 extended this
> handling to static member functions; I think that's wrong, and have
> opened CWG2834 to address that and how explicit object member functions
> interact with it.
>
> The FIXME comments are to guide how the explicit object member function
> support should change the uses of DECL_NONSTATIC_MEMBER_FUNCTION_P.
>
> The library testsuite changes are to make partial ordering work again
> between the generic operator- in the testcase and
> _Pointer_adapter::operator-.
>
> DR 532
> PR c++/53499
>
> gcc/cp/ChangeLog:
>
> * pt.cc (more_specialized_fn): Fix object parameter handling.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/partial-order4.C: New test.
> * g++.dg/template/spec26.C: Adjust for CWG532.
>
> libstdc++-v3/ChangeLog:
>
> * testsuite/23_containers/vector/ext_pointer/types/1.cc
> * testsuite/23_containers/vector/ext_pointer/types/2.cc
> (N::operator-): Make less specialized.
> ---
> gcc/cp/pt.cc | 68 ++++++++++++++-----
> .../g++.dg/template/partial-order4.C | 17 +++++
> gcc/testsuite/g++.dg/template/spec26.C | 10 +--
> .../vector/ext_pointer/types/1.cc | 4 +-
> .../vector/ext_pointer/types/2.cc | 4 +-
> 5 files changed, 78 insertions(+), 25 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/template/partial-order4.C
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 924a20973b4..4b2af4f7aca 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -25218,27 +25218,61 @@ more_specialized_fn (tree pat1, tree pat2, int len)
> bool lose1 = false;
> bool lose2 = false;
>
> - /* Remove the this parameter from non-static member functions. If
> - one is a non-static member function and the other is not a static
> - member function, remove the first parameter from that function
> - also. This situation occurs for operator functions where we
> - locate both a member function (with this pointer) and non-member
> - operator (with explicit first operand). */
> - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1))
> + /* C++17 [temp.func.order]/3 (CWG532)
> +
> + If only one of the function templates M is a non-static member of some
> + class A, M is considered to have a new first parameter inserted in its
> + function parameter list. Given cv as the cv-qualifiers of M (if any), the
> + new parameter is of type "rvalue reference to cv A" if the optional
> + ref-qualifier of M is && or if M has no ref-qualifier and the first
> + parameter of the other template has rvalue reference type. Otherwise, the
> + new parameter is of type "lvalue reference to cv A". */
> +
> + if (DECL_STATIC_FUNCTION_P (decl1) || DECL_STATIC_FUNCTION_P (decl2))
> {
> - len--; /* LEN is the number of significant arguments for DECL1 */
> - args1 = TREE_CHAIN (args1);
> - if (!DECL_STATIC_FUNCTION_P (decl2))
> - args2 = TREE_CHAIN (args2);
> - }
> - else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
> - {
> - args2 = TREE_CHAIN (args2);
> - if (!DECL_STATIC_FUNCTION_P (decl1))
> + /* Note C++20 DR2445 extended the above to static member functions, but
> + I think think the old G++ behavior of just skipping the object
> + parameter when comparing to a static member function was better, so
> + let's stick with that for now. This is CWG2834. --jason 2023-12 */
> + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1)) /* FIXME or explicit */
> {
> - len--;
> + len--; /* LEN is the number of significant arguments for DECL1 */
> args1 = TREE_CHAIN (args1);
> }
> + else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2)) /* FIXME or explicit */
> + args2 = TREE_CHAIN (args2);
> + }
> + else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1) /* FIXME implicit only */
> + && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
> + {
> + /* Note DR2445 also (IMO wrongly) removed the "only one" above, which
> + would break e.g. cpp1y/lambda-generic-variadic5.C. */
> + len--;
> + args1 = TREE_CHAIN (args1);
> + args2 = TREE_CHAIN (args2);
> + }
> + else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1) /* FIXME implicit only */
> + || DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
> + {
> + /* The other is a non-member or explicit object member function;
> + rewrite the implicit object parameter to a reference. */
> + tree ns = DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2) ? decl2 : decl1;
> + tree &nsargs = ns == decl2 ? args2 : args1;
> + tree obtype = TREE_TYPE (TREE_VALUE (nsargs));
> +
> + nsargs = TREE_CHAIN (nsargs);
> +
> + cp_ref_qualifier rqual = type_memfn_rqual (TREE_TYPE (ns));
> + if (rqual == REF_QUAL_NONE)
> + {
> + tree otherfirst = ns == decl1 ? args2 : args1;
> + otherfirst = TREE_VALUE (otherfirst);
> + if (TREE_CODE (otherfirst) == REFERENCE_TYPE
> + && TYPE_REF_IS_RVALUE (otherfirst))
> + rqual = REF_QUAL_RVALUE;
> + }
> + obtype = cp_build_reference_type (obtype, rqual == REF_QUAL_RVALUE);
> + nsargs = tree_cons (NULL_TREE, obtype, nsargs);
> }
>
> /* If only one is a conversion operator, they are unordered. */
> diff --git a/gcc/testsuite/g++.dg/template/partial-order4.C b/gcc/testsuite/g++.dg/template/partial-order4.C
> new file mode 100644
> index 00000000000..89555ab7060
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/partial-order4.C
> @@ -0,0 +1,17 @@
> +// DR 532
> +// PR c++/53499
> +// [temp.func.order] says that we do ordering on the first parameter.
> +
> +struct A
> +{
> + template <class T>
> + bool operator==(T);
> +};
> +
> +template <class T, class U>
> +bool operator==(T, U);
> +
> +int main()
> +{
> + A() == A();
> +}
> diff --git a/gcc/testsuite/g++.dg/template/spec26.C b/gcc/testsuite/g++.dg/template/spec26.C
> index fad8e3e1519..253d4211153 100644
> --- a/gcc/testsuite/g++.dg/template/spec26.C
> +++ b/gcc/testsuite/g++.dg/template/spec26.C
> @@ -1,13 +1,15 @@
> -// { dg-do run }
> +// { dg-do compile { target c++11 } }
> // Copyright (C) 2005 Free Software Foundation, Inc.
> // Contributed by Nathan Sidwell 16 Sep 2005 <nathan@codesourcery.com>
>
> // PR 23519 template specialization ordering (DR214)
> // Origin: Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
>
> +// DR532 clarified that the * expression is ambiguous.
> +
> struct A
> {
> - template<class T> int operator+(T&) { return 1;}
> + template<class T> int operator+(T&) = delete;
> };
>
> template<class T> struct B
> @@ -16,7 +18,7 @@ template<class T> struct B
> template<typename R> int operator*(R&) {return 3;}
> };
>
> -template <typename T, typename R> int operator-(B<T>, R&) {return 4;}
> +template <typename T, typename R> int operator-(B<T>, R&) = delete;
> template<class T> int operator+(A&, B<T>&) { return 5;}
> template <typename T> int operator*(T &, A&){return 6;}
>
> @@ -30,6 +32,6 @@ int main()
> if ((b - a) != 2)
> return 2;
>
> - if ((b * a) != 6)
> + if ((b * a) != 6) // { dg-error "ambiguous" }
> return 3;
> }
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc
> index 5b3c673898e..2819851076c 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/1.cc
> @@ -36,8 +36,8 @@ namespace N
> X operator+(T, std::size_t)
> { return X(); }
>
> - template<typename T>
> - X operator-(T, T)
> + template<typename T, typename U>
> + X operator-(T, U)
> { return X(); }
> }
>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc
> index cc9519ee618..6c00d1568ae 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/ext_pointer/types/2.cc
> @@ -38,8 +38,8 @@ namespace N
> X operator+(T, std::size_t)
> { return X(); }
>
> - template<typename T>
> - X operator-(T, T)
> + template<typename T, typename U>
> + X operator-(T, U)
> { return X(); }
> }
>
>
> base-commit: 0e7fee57c00ae17611651e0b057dc03b6e276b82
> --
> 2.39.3
>
More information about the Libstdc++
mailing list