Skip to content

Commit 8d35324

Browse files
committed
test: add unit tests for fixed UFCS corner cases
1 parent e4d3c81 commit 8d35324

25 files changed

+662
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
namespace ns {
2+
3+
template<bool> struct t { };
4+
constexpr bool f(const t<true>&) { return true; }
5+
constexpr t<true> o{};
6+
7+
} // namespace ns
8+
9+
ns: namespace = {
10+
11+
// Variables.
12+
13+
v0: <_: t<o.f()>> bool == false; // Fails on GCC ([GCC109781][]).
14+
15+
v1: t<o.f()> == t<true>(); // Fails on Clang 12 (lambda in unevaluated context).
16+
17+
v2: bool == o.f();
18+
19+
// Functions.
20+
21+
g: <_: t<o.f()>> () = { } // Fails on GCC ([GCC109781][]).
22+
23+
g: (_: t<o.f()>) = { } // Fails on Clang 12 (lambda in unevaluated context).
24+
25+
g: () pre(o.f()) = { }
26+
27+
h: () -> t<o.f()> = o; // Fails on Clang 12 (lambda in unevaluated context).
28+
29+
// Aliases.
30+
31+
a: <_: t<o.f()>> type == bool; // Fails on GCC ([GCC109781][]).
32+
33+
b: <_: t<o.f()>> _ == false; // Fails on GCC ([GCC109781][]).
34+
35+
c: type == t<o.f()>; // Fails on Clang 12 (lambda in unevaluated context).
36+
37+
d: _ == t<o.f()>(); // Fails on Clang 12 (lambda in unevaluated context).
38+
39+
} // namespace ns
40+
41+
main: () = { }
42+
43+
// [GCC109781]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109781
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
print_res: (x: i32) -> i32 = {
2+
std::cout << x;
3+
if x == 9 { std::cout << '\n'; }
4+
return x;
5+
}
6+
7+
t: @struct type = {
8+
f: (inout this) -> i32 = print_res(0);
9+
f: (inout this, _) -> i32 = print_res(1);
10+
f: <_> (inout this) -> i32 = print_res(2);
11+
f: <_> (inout this, _) -> i32 = print_res(3);
12+
f: <_, U> (inout this, _, _) -> i32 = print_res(4);
13+
}
14+
15+
f: (_: t) -> i32 = print_res(5);
16+
f: (_: t, _) -> i32 = print_res(6);
17+
f: <_> (_: t) -> i32 = print_res(7);
18+
f: <_> (_: t, _) -> i32 = print_res(8);
19+
f: <_, U> (_: t, _, _) -> i32 = print_res(9);
20+
21+
m: t = ();
22+
n: const t = ();
23+
a: <_, U> _ == n;
24+
25+
_: i32 = m.f();
26+
_: i32 = m.f(0);
27+
_: i32 = m.f<t>();
28+
_: i32 = m.f<t>(0);
29+
_: i32 = m.f<t, t>(0, 0);
30+
_: i32 = n.f();
31+
_: i32 = n.f(0);
32+
_: i32 = n.f<t>();
33+
_: i32 = n.f<t>(0);
34+
_: i32 = n.f<t, t>(0, 0);
35+
_: i32 = a<t, t>.f<t, t>(0, 0);
36+
37+
main: () = {
38+
_ = m.f();
39+
_ = m.f(0);
40+
_ = m.f<t>();
41+
_ = m.f<t>(0);
42+
_ = m.f<t, t>(0, 0);
43+
_ = n.f();
44+
_ = n.f(0);
45+
_ = n.f<t>();
46+
_ = n.f<t>(0);
47+
_ = n.f<t, t>(0, 0);
48+
_ = a<t, t>.f<t, t>(0, 0);
49+
50+
_ = :(a, f) = { _ = a.f(a).f(); };
51+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
identity: @struct type = {
2+
operator(): (this, forward x) -> forward _ == x;
3+
}
4+
5+
t: @struct type = {
6+
f: (this) -> int == 0;
7+
}
8+
9+
u: @struct type = { }
10+
11+
ns: namespace = {
12+
f: (_) -> int == 1;
13+
} // namespace ns
14+
15+
// v: @struct type = {
16+
// f :== :(_) 0; // Pending on #706.
17+
// g: (i) i.f();
18+
// }
19+
20+
main: () = {
21+
{
22+
f := t().f();
23+
assert(f == 0);
24+
}
25+
{
26+
f: _ = t().f();
27+
assert(f == 0);
28+
}
29+
(f := t().f()) assert(f == 0);
30+
(f: _ = t().f()) assert(f == 0);
31+
{
32+
f :== t().f();
33+
static_assert(f == 0);
34+
}
35+
{
36+
f: _ == t().f();
37+
static_assert(f == 0);
38+
}
39+
{
40+
f := :(f) -> _ = {
41+
assert(t().f() == 0);
42+
return u().f();
43+
}(identity());
44+
_ = f;
45+
}
46+
{ // Rejected by MSVC.
47+
// f := :<f: _> (copy _: std::integral_constant<identity, f>) -> _ = {
48+
// assert(t().f() == 0);
49+
// return u().f();
50+
// }(:std::integral_constant<identity, (:identity = ())> = ());
51+
// _ = f;
52+
}
53+
{
54+
f := :() = {
55+
(f: identity = identity()) assert(t().f() == 0);
56+
(f: identity = identity()) _ = u().f();
57+
};
58+
_ = f;
59+
}
60+
{
61+
f := :() = {
62+
using ns::f;
63+
static_assert(t().f() == 0);
64+
static_assert(u().f() == 1);
65+
};
66+
_ = f;
67+
}
68+
{
69+
f := :() = {
70+
static_assert(t().f() == 0);
71+
g := :<T> (_: T) -> std::void_t<decltype(T().f())> = {};
72+
static_assert(!std::is_invocable_v<decltype(g), u>);
73+
using ns::f;
74+
};
75+
_ = f;
76+
}
77+
{
78+
f := :() = {
79+
using ns::f;
80+
_ = :() = {
81+
static_assert(t().f() == 0);
82+
static_assert(u().f() == 1);
83+
};
84+
{
85+
static_assert(t().f() == 0);
86+
static_assert(u().f() == 1);
87+
}
88+
};
89+
_ = f;
90+
}
91+
{
92+
f := :() = {
93+
_ = :() = {
94+
static_assert(t().f() == 0);
95+
g := :<T> (_: T) -> std::void_t<decltype(T().f())> = {};
96+
static_assert(!std::is_invocable_v<decltype(g), u>);
97+
};
98+
{
99+
static_assert(t().f() == 0);
100+
g := :<T> (_: T) -> std::void_t<decltype(T().f())> = {};
101+
static_assert(!std::is_invocable_v<decltype(g), u>);
102+
}
103+
using ns::f;
104+
};
105+
_ = f;
106+
}
107+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
t: type = {
2+
swap: (virtual inout this, that) = { } // Non-`virtual` blocked on #508, idiomatic form on #507.
3+
}
4+
main: () = {
5+
static_assert(noexcept(t().swap(t()))); // Fails on Clang 12 (lambda in unevaluated context).
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
f: <T> () -> std::type_identity_t<decltype(T().a())> = { } // Fails on Clang 12 (lambda in unevaluated context).
2+
3+
B: type = { }
4+
5+
main: () = {
6+
g := :<T> (_: T) -> std::void_t<decltype(f<T>())> = {};
7+
static_assert(!std::is_invocable_v<decltype(g), B>);
8+
}

regression-tests/test-results/clang-18/mixed-bugfix-for-ufcs-non-local.cpp.execution

Whitespace-only changes.

regression-tests/test-results/clang-18/mixed-bugfix-for-ufcs-non-local.cpp.output

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
0123456789
2+
9
3+
0123456789
4+
9

regression-tests/test-results/clang-18/pure2-bugfix-for-ufcs-arguments.cpp.output

Whitespace-only changes.

regression-tests/test-results/clang-18/pure2-bugfix-for-ufcs-name-lookup.cpp.execution

Whitespace-only changes.

regression-tests/test-results/clang-18/pure2-bugfix-for-ufcs-name-lookup.cpp.output

Whitespace-only changes.

regression-tests/test-results/clang-18/pure2-bugfix-for-ufcs-noexcept.cpp.execution

Whitespace-only changes.

regression-tests/test-results/clang-18/pure2-bugfix-for-ufcs-noexcept.cpp.output

Whitespace-only changes.

regression-tests/test-results/clang-18/pure2-bugfix-for-ufcs-sfinae.cpp.execution

Whitespace-only changes.

regression-tests/test-results/clang-18/pure2-bugfix-for-ufcs-sfinae.cpp.output

Whitespace-only changes.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
3+
//=== Cpp2 type declarations ====================================================
4+
5+
6+
#include "cpp2util.h"
7+
8+
9+
#line 9 "mixed-bugfix-for-ufcs-non-local.cpp2"
10+
namespace ns {
11+
12+
#line 39 "mixed-bugfix-for-ufcs-non-local.cpp2"
13+
}
14+
15+
16+
//=== Cpp2 type definitions and function declarations ===========================
17+
18+
namespace ns {
19+
20+
template<bool> struct t { };
21+
constexpr bool f(const t<true>&) { return true; }
22+
constexpr t<true> o{};
23+
24+
} // namespace ns
25+
26+
#line 9 "mixed-bugfix-for-ufcs-non-local.cpp2"
27+
namespace ns {
28+
29+
// Variables.
30+
31+
template<t<CPP2_UFCS_NONLOCAL(f)(o)> _> bool inline constexpr v0 = false;// Fails on GCC ([GCC109781][]).
32+
33+
t<CPP2_UFCS_NONLOCAL(f)(o)> inline constexpr v1 = t<true>();// Fails on Clang 12 (lambda in unevaluated context).
34+
35+
bool inline constexpr v2 = CPP2_UFCS_NONLOCAL(f)(o);
36+
37+
// Functions.
38+
39+
template<t<CPP2_UFCS_NONLOCAL(f)(o)> _> auto g() -> void;
40+
41+
auto g([[maybe_unused]] cpp2::in<t<CPP2_UFCS_NONLOCAL(f)(o)>> param1) -> void;
42+
43+
auto g() -> void;
44+
45+
[[nodiscard]] auto h() -> t<CPP2_UFCS_NONLOCAL(f)(o)>;
46+
47+
// Aliases.
48+
49+
template<t<CPP2_UFCS_NONLOCAL(f)(o)> _> using a = bool;// Fails on GCC ([GCC109781][]).
50+
51+
template<t<CPP2_UFCS_NONLOCAL(f)(o)> _> auto inline constexpr b = false;// Fails on GCC ([GCC109781][]).
52+
53+
using c = t<CPP2_UFCS_NONLOCAL(f)(o)>;// Fails on Clang 12 (lambda in unevaluated context).
54+
55+
auto inline constexpr d = t<CPP2_UFCS_NONLOCAL(f)(o)>();// Fails on Clang 12 (lambda in unevaluated context).
56+
57+
} // namespace ns
58+
59+
auto main() -> int;
60+
61+
// [GCC109781]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109781
62+
63+
64+
//=== Cpp2 function definitions =================================================
65+
66+
67+
#line 9 "mixed-bugfix-for-ufcs-non-local.cpp2"
68+
namespace ns {
69+
70+
#line 21 "mixed-bugfix-for-ufcs-non-local.cpp2"
71+
template<t<CPP2_UFCS_NONLOCAL(f)(o)> _> auto g() -> void{}// Fails on GCC ([GCC109781][]).
72+
73+
auto g([[maybe_unused]] cpp2::in<t<CPP2_UFCS_NONLOCAL(f)(o)>> param1) -> void{}// Fails on Clang 12 (lambda in unevaluated context).
74+
75+
auto g() -> void{
76+
cpp2::Default.expects(CPP2_UFCS(f)(o), "");
77+
#line 25 "mixed-bugfix-for-ufcs-non-local.cpp2"
78+
}
79+
80+
[[nodiscard]] auto h() -> t<CPP2_UFCS_NONLOCAL(f)(o)> { return o; }// Fails on Clang 12 (lambda in unevaluated context).
81+
82+
#line 39 "mixed-bugfix-for-ufcs-non-local.cpp2"
83+
}
84+
85+
auto main() -> int{}
86+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mixed-bugfix-for-ufcs-non-local.cpp2... ok (mixed Cpp1/Cpp2, Cpp2 code passes safety checks)
2+

0 commit comments

Comments
 (0)