Hi! The spaceship-synth-neg6.C testcase ICEs because we call cat_tag_for on the explicit return type, but pointer types don't have TYPE_LINKAGE_IDENTIFIER. The patch fixes that. Or should I be checking for if (!CLASS_TYPE_P (type)) return cc_last; instead (are class type guaranteed to have TYPE_LINKAGE_IDENTIFIER?)? I also wonder if after finding a match we shouldn't verify if is a class type in std namespace (i.e. that TYPE_NAME (TYPE_MAIN_VARIANT (type)) is a TYPE_DECL and decl_in_std_namespace_p (TYPE_NAME (TYPE_MAIN_VARIANT (type))) because it seems nothing prevents it from returning non-cc_last say on namespace N { struct partial_ordering {}; } etc.
The g++.dg/cpp2a/spaceship-synth11.C testcase is from a PR that has been fixed with r12-619-gfc178519771db508c03611cff4a1466cf67fce1d (but not backported to 11). Bootstrapped/regtested on x86_64-linux and i686-linux. 2021-08-10 Jakub Jelinek <ja...@redhat.com> gcc/cp/ PR c++/94162 * method.c (cat_tag_for): Return cc_last for types with no linkage identifier. gcc/testsuite/ PR c++/99429 * g++.dg/cpp2a/spaceship-synth11.C: New test. PR c++/94162 * g++.dg/cpp2a/spaceship-synth-neg6.C: New test. --- gcc/cp/method.c.jj 2021-06-25 10:36:22.169019953 +0200 +++ gcc/cp/method.c 2021-08-09 12:26:38.590166006 +0200 @@ -1029,6 +1029,8 @@ is_cat (tree type, comp_cat_tag tag) static comp_cat_tag cat_tag_for (tree type) { + if (!TYPE_LINKAGE_IDENTIFIER (type)) + return cc_last; for (int i = 0; i < cc_last; ++i) { comp_cat_tag tag = (comp_cat_tag)i; --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C.jj 2021-08-09 12:28:58.748240310 +0200 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C 2021-08-09 12:29:44.023618250 +0200 @@ -0,0 +1,29 @@ +// PR c++/99429 +// { dg-do compile { target c++20 } } + +namespace std { +struct strong_ordering { + int _v; + constexpr strong_ordering (int v) :_v(v) {} + constexpr operator int (void) const { return _v; } + static const strong_ordering less; + static const strong_ordering equal; + static const strong_ordering greater; +}; +constexpr strong_ordering strong_ordering::less = -1; +constexpr strong_ordering strong_ordering::equal = 0; +constexpr strong_ordering strong_ordering::greater = 1; +} + +template <unsigned long N> +struct duration { + static constexpr const long period = N; + constexpr duration (void) = default; + constexpr duration (const duration& d) = default; + constexpr bool operator== (const duration& d) const = default; + constexpr bool operator<=> (const duration& d) const = default; + long _d; +}; + +using nanoseconds = duration<1>; +using microseconds = duration<nanoseconds::period * 1000>; --- gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C.jj 2021-08-09 12:31:47.411922957 +0200 +++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C 2021-08-09 12:35:26.995906403 +0200 @@ -0,0 +1,11 @@ +// PR c++/94162 +// { dg-do compile { target c++20 } } + +#include <compare> + +struct S { + int a; // { dg-error "three-way comparison of 'S::a' has type 'std::strong_ordering', which does not convert to 'int\\*'" } + int *operator<=>(const S&) const = default; +}; + +bool b = S{} < S{}; // { dg-error "use of deleted function 'constexpr int\\* S::operator<=>\\\(const S&\\\) const'" } Jakub