File: p4.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,998,520 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (182 lines) | stat: -rw-r--r-- 6,840 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx2a %s
// RUN: %clang_cc1 -std=c++23 -verify=expected %s

// This test is for [class.compare.default]p3 as modified and renumbered to p4
// by P2002R0.
// Also covers modifications made by P2448R2

namespace std {
  struct strong_ordering {
    int n;
    constexpr operator int() const { return n; }
    static const strong_ordering less, equal, greater;
  };
  constexpr strong_ordering strong_ordering::less = {-1};
  constexpr strong_ordering strong_ordering::equal = {0};
  constexpr strong_ordering strong_ordering::greater = {1};
}

namespace N {
  struct A {
    friend constexpr std::strong_ordering operator<=>(const A&, const A&) = default; // expected-note 2{{declared here}}
  };

  constexpr std::strong_ordering (*test_a_threeway_not_found)(const A&, const A&) = &operator<=>; // expected-error {{undeclared}}

  constexpr std::strong_ordering operator<=>(const A&, const A&) noexcept;
  constexpr std::strong_ordering (*test_a_threeway)(const A&, const A&) = &operator<=>;
  static_assert(!(*test_a_threeway)(A(), A())); // expected-error {{static assertion expression is not an integral constant expression}}
                                               // expected-note@-1 {{undefined function 'operator<=>' cannot be used in a constant expression}}

  constexpr bool (*test_a_equal_not_found)(const A&, const A&) = &operator==; // expected-error {{undeclared}}

  constexpr bool operator==(const A&, const A&) noexcept;
  constexpr bool (*test_a_equal)(const A&, const A&) noexcept = &operator==;
  static_assert((*test_a_equal)(A(), A())); // expected-error {{static assertion expression is not an integral constant expression}}
                                            // expected-note@-1 {{undefined function 'operator==' cannot be used in a constant expression}}
}

struct B1 {
  virtual std::strong_ordering operator<=>(const B1&) const = default;
};
bool (B1::*test_b)(const B1&) const = &B1::operator==;

struct C1 : B1 {
  // OK, B1::operator== is virtual.
  bool operator==(const B1&) const override;
};

struct B2 {
  std::strong_ordering operator<=>(const B2&) const = default;
};

struct C2 : B2 {
  bool operator==(const B2&) const override; // expected-error {{only virtual member functions}}
};

struct D {
  std::strong_ordering operator<=>(const D&) const;
  virtual std::strong_ordering operator<=>(const struct E&) const = 0;
};
struct E : D {
  // expected-error@+2 {{only virtual member functions}}
  // expected-note@+1 {{while declaring the corresponding implicit 'operator==' for this defaulted 'operator<=>'}}
  std::strong_ordering operator<=>(const E&) const override = default;
};

struct F {
  [[deprecated("oh no")]] std::strong_ordering operator<=>(const F&) const = default; // expected-note 4{{deprecated}}
};
void use_f(F f) {
  void(f <=> f); // expected-warning {{oh no}}
  void(f < f); // expected-warning {{oh no}}
  void(f == f); // expected-warning {{oh no}}
  void(f != f); // expected-warning {{oh no}}
}

class G {
  // expected-note@+2 {{implicitly declared private here}}
  // expected-note-re@+1 {{{{^}}declared private here}}
  std::strong_ordering operator<=>(const G&) const = default;
public:
};
void use_g(G g) {
  void(g <=> g); // expected-error {{private}}
  void(g == g); // expected-error {{private}}
}

struct H {
  bool operator==(const H&) const; // cxx2a-note {{non-constexpr comparison function declared here}}
  constexpr std::strong_ordering operator<=>(const H&) const { return std::strong_ordering::equal; }
};

struct I {
  H h; // cxx2a-note {{non-constexpr comparison function would be used to compare member 'h'}}
  constexpr std::strong_ordering operator<=>(const I&) const = default; // cxx2a-error {{cannot be declared constexpr}}
};

struct J {
  std::strong_ordering operator<=>(const J&) const & = default; // expected-note {{candidate function (the implicit 'operator==' for this 'operator<=>)'}}
  friend std::strong_ordering operator<=>(const J&, const J&) = default; // expected-note {{candidate function (the implicit 'operator==' for this 'operator<=>)'}}
};
void use_j(J j) {
  void(j == j); // expected-error {{ambiguous}}
}

namespace DeleteAfterFirstDecl {
  bool operator==(const struct Q&, const struct Q&);
  struct Q {
    struct X {
      friend std::strong_ordering operator<=>(const X&, const X&);
    } x; // expected-note {{no viable 'operator=='}}
    // expected-error@+1 {{defaulting the corresponding implicit 'operator==' for this defaulted 'operator<=>' would delete it after its first declaration}}
    friend std::strong_ordering operator<=>(const Q&, const Q&) = default;
  };
}

// Note, substitution here results in the second parameter of 'operator=='
// referring to the first parameter of 'operator==', not to the first parameter
// of 'operator<=>'.
// FIXME: Find a case where this matters (attribute enable_if?).
struct K {
  friend std::strong_ordering operator<=>(const K &k, decltype(k)) = default;
};
bool test_k = K() == K();

namespace NoInjectionIfOperatorEqualsDeclared {
  struct A {
    void operator==(int); // expected-note 2{{not viable}}
    std::strong_ordering operator<=>(const A&) const = default;
  };
  bool test_a = A() == A(); // expected-error {{invalid operands}}

  struct B {
    friend void operator==(int, struct Q); // expected-note 2{{not viable}}
    std::strong_ordering operator<=>(const B&) const = default;
  };
  bool test_b = B() == B(); // expected-error {{invalid operands}}

  struct C {
    void operator==(int); // expected-note 2{{not viable}}
    friend std::strong_ordering operator<=>(const C&, const C&) = default;
  };
  bool test_c = C() == C(); // expected-error {{invalid operands}}

  struct D {
    void f() {
      void operator==(const D&, int);
    }
    struct X {
      friend void operator==(const D&, int);
    };
    friend std::strong_ordering operator<=>(const D&, const D&) = default;
  };
  bool test_d = D() == D();
}

namespace GH61238 {
template <typename A> struct my_struct {
    A value; // cxx2a-note {{non-constexpr comparison function would be used to compare member 'value'}}

    constexpr friend bool operator==(const my_struct &, const my_struct &) noexcept = default; // cxx2a-error {{cannot be declared constexpr}}
};

struct non_constexpr_type {
    friend bool operator==(non_constexpr_type, non_constexpr_type) noexcept { // cxx2a-note {{non-constexpr comparison function declared here}}
        return false;
    }
};

my_struct<non_constexpr_type> obj; // cxx2a-note {{in instantiation of template class 'GH61238::my_struct<GH61238::non_constexpr_type>' requested here}}
}

namespace Constrained {
  template<typename T>
  struct A {
    std::strong_ordering operator<=>(const A&) const requires true = default;
  };

  bool f(A<int> a) {
    return a != A<int>();
  }
}