Skip to content

Commit 591cd4b

Browse files
committed
fix(to_cpp1): improve recognition of dependent types and deducible parameters
1 parent 05ce45a commit 591cd4b

17 files changed

+775
-61
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Dependent, non-deducible parameters
2+
// are wrapped like non-dependent parameters.
3+
init: <T> (out x: std::integral_constant<i32, T::value>) = { x = (); }
4+
init: <T> (out x: std::integral_constant<i32, T::value>, _: T) = { x = (); }
5+
id: <T> (x: std::integral_constant<i32, T::value>) -> forward _ = x;
6+
id: <T> (x: std::integral_constant<i32, T::value>, y: T) = { assert(x& == y&); }
7+
8+
main: () = {
9+
zero: type == std::integral_constant<i32, 0>;
10+
11+
z: zero;
12+
init<zero>(out z);
13+
assert(id<zero>(z)& == z&);
14+
15+
// Deducible parameters.
16+
_ = :v = 0;
17+
_ = :<T> (x: std::vector<T>) = {}(:std::vector<i32> = ());
18+
_ = :<T> (x: std::vector<std::vector<T>>) = {}(:std::vector<std::vector<i32>> = ());
19+
// _ = :<T, U> (x: std::pair<T, typename U::value_type>, y: U) = {}(:std::pair = (0, 0), z); // Blocked on #727.
20+
_ = :<T, U> (x: std::array<T, U::value>, y: U) = {}(:std::array<i32, 0> = (), z);
21+
init(out z, z);
22+
id(z, z);
23+
24+
// Test that these are emitted unwrapped in case they are deducible.
25+
(copy f := :<T> (x: std::vector<std::type_identity_t<T>>) = {})
26+
static_assert(!std::is_invocable_v<decltype(f), std::vector<i32>>, "`T` is non-deducible.");
27+
(copy f := :<T> (x: std::vector<std::vector<T>>) = {})
28+
static_assert(std::is_invocable_v<decltype(f), std::vector<std::vector<i32>>>, "`T` is deducible.");
29+
}
30+
31+
v: <T> type = {
32+
operator=: (out this, x: T) = { }
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
main: () = {
2+
a: type == b;
3+
b: type == a;
4+
_ = a::t;
5+
_ = b::t;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
identity: <T> type == T;
2+
3+
f: <T, V: T::value_type> (x: T::value_type) -> T::value_type = {
4+
assert(x is T::value_type);
5+
y: T::value_type;
6+
y = x;
7+
z: type == T::value_type;
8+
return (:T::value_type = x);
9+
10+
// Dependent *template-id*s.
11+
_ = :identity<T>::value_type = (); // First identifier.
12+
_ = :std::optional<T>::value_type = (); // Non-first identifier.
13+
_ = :std::array<i32, T::value>::value_type = ();
14+
_ = :std::array<i32, T::value + T::value>::value_type = ();
15+
16+
// Emitted `template`.
17+
ptr: type == * T; // Also test lookup through type aliases.
18+
nptr: type == * i32;
19+
_ = :std::pointer_traits<ptr>::rebind<ptr> = (); // Type-only context.
20+
_ = :std::pointer_traits<nptr>::rebind<nptr> = (); // Non-dependent.
21+
_ = :std::pointer_traits<nptr>::rebind<ptr> = (); // Dependent on the nested template.
22+
_ = :std::pointer_traits<ptr>::rebind<nptr> = (); // Dependent on the outer template.
23+
// _ = :identity<typename std::pointer_traits<ptr>::rebind<ptr>> = (); // Non type-only context. Blocked on #727.
24+
25+
// Aliases.
26+
w: type == T;
27+
_ = :w::value_type = x;
28+
v: type == w;
29+
_ = :v::value_type = x;
30+
a: type == T::type;
31+
_ = :a::value_type = x;
32+
33+
{
34+
// Test that there's no prefixed `typename` to....
35+
_ = std::integral_constant<i32, T::value>(); // `T::value`.
36+
_ = :std::type_identity_t<T> = (); // `std::type_identity_t<T>`.
37+
38+
// Test that non-dependent names aren't emitted with `typename`.
39+
a: type == std::integral_constant<i32, 0>;
40+
b: type == a;
41+
c: type == b;
42+
_ = :b::value_type = x;
43+
_ = :c::value_type = x;
44+
}
45+
}
46+
47+
t: @struct <T: type> type = {
48+
u: @struct type = {
49+
x: T::value_type = ();
50+
this: T::type = ();
51+
}
52+
x: T::value_type = 0;
53+
}
54+
55+
main: () = {
56+
zero: type == std::integral_constant<i32, 0>;
57+
_ = f<zero, 0>(0);
58+
59+
// clang-format off
60+
_ = : ::t<zero> = (); // clang-format on
61+
62+
// Emitted `template` (noop, taken care of by the UFCS macro).
63+
_ = (:<T> () = {}).operator()<i32>();
64+
65+
// Nesting is not relevant to lookup.
66+
_ = :<T> () = { _ = :T::value_type = (); };
67+
_ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; };
68+
_ = :() = { _ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; }; };
69+
_ = :() = { _ = :() = { _ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; }; }; };
70+
_ = :() = { _ = :() = { _ = :<T> () = { _ = :() = { _ = :T::value_type = (); }; }; }; };
71+
_ = :() = { _ = :<T> () = { _ = :() = { _ = :() = { _ = :T::value_type = (); }; }; }; };
72+
_ = :<T> () = { _ = :() = { _ = :() = { _ = :() = { _ = :T::value_type = (); }; }; }; };
73+
_ = :<T> () = { _ = :() = { _ = :() = { _ = :(x: T::value_type) = {}; }; }; };
74+
_ = :<T> () = { _ = :() = { _ = :(x: T::value_type) = { _ = :() = {}; }; }; };
75+
_ = :<T> () = { _ = :(x: T::value_type) = { _ = :() = { _ = :() = {}; }; }; };
76+
_ = :<T> (x: T::value_type) = { _ = :() = { _ = :() = { _ = :() = {}; }; }; };
77+
78+
// Lookup.
79+
{
80+
alias: type == std::integral_constant<i32, 0>;
81+
_ = :alias::value_type = 0; // Non-dependent.
82+
}
83+
_ = :<T> (_: T) = {
84+
alias: type == std::integral_constant<T, 0>;
85+
_ = :alias::value_type = 0; // Dependent.
86+
{
87+
alias: type == std::integral_constant<i32, 0>;
88+
_ = :alias::value_type = 0; // Non-dependent.
89+
}
90+
}(0);
91+
92+
_ = :(r) -> std::type_identity_t<decltype(begin(r)*)> = r[0];(std::vector<int>(1));
93+
}

regression-tests/test-results/gcc-13/gcc-version.output

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
gcc (GCC) 13.2.1 20231011 (Red Hat 13.2.1-4)
1+
c++ (GCC) 13.2.1 20230801
22
Copyright (C) 2023 Free Software Foundation, Inc.
33
This is free software; see the source for copying conditions. There is NO
44
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

regression-tests/test-results/gcc-13/pure2-bugfix-for-deducible-parameters.cpp.execution

Whitespace-only changes.

regression-tests/test-results/gcc-13/pure2-bugfix-for-deducible-parameters.cpp.output

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pure2-bugfix-for-dependent-types-recursion.cpp2: In function ‘int main()’:
2+
pure2-bugfix-for-dependent-types-recursion.cpp2:2:13: error: ‘b’ does not name a type
3+
2 | a: type == b;
4+
| ^
5+
pure2-bugfix-for-dependent-types-recursion.cpp2:3:13: error: ‘a’ does not name a type
6+
3 | b: type == a;
7+
| ^
8+
pure2-bugfix-for-dependent-types-recursion.cpp2:4:21: error: ‘a’ has not been declared
9+
4 | _ = a::t;
10+
| ^
11+
pure2-bugfix-for-dependent-types-recursion.cpp2:5:21: error: ‘b’ has not been declared
12+
5 | _ = b::t;
13+
| ^

regression-tests/test-results/gcc-13/pure2-bugfix-for-dependent-types.cpp.execution

Whitespace-only changes.

regression-tests/test-results/gcc-13/pure2-bugfix-for-dependent-types.cpp.output

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2"
10+
11+
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2"
12+
template<typename T> class v;
13+
14+
15+
//=== Cpp2 type definitions and function declarations ===========================
16+
17+
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2"
18+
// Dependent, non-deducible parameters
19+
// are wrapped like non-dependent parameters.
20+
#line 3 "pure2-bugfix-for-deducible-parameters.cpp2"
21+
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x) -> void;
22+
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& unnamed_param_2) -> void;
23+
template<typename T> [[nodiscard]] auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x) -> auto&&;
24+
template<typename T> auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void;
25+
26+
auto main() -> int;
27+
28+
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2"
29+
template<typename T> class v {
30+
public: explicit v(T const& x);
31+
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2"
32+
public: auto operator=(T const& x) -> v& ;
33+
public: v(v const&) = delete; /* No 'that' constructor, suppress copy */
34+
public: auto operator=(v const&) -> void = delete;
35+
36+
#line 33 "pure2-bugfix-for-deducible-parameters.cpp2"
37+
};
38+
39+
40+
//=== Cpp2 function definitions =================================================
41+
42+
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2"
43+
44+
#line 3 "pure2-bugfix-for-deducible-parameters.cpp2"
45+
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x) -> void{x.construct(); }
46+
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& unnamed_param_2) -> void{x.construct(); }
47+
template<typename T> [[nodiscard]] auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x) -> auto&& { return x; }
48+
template<typename T> auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void{cpp2::Default.expects(&x == &y, ""); }
49+
50+
auto main() -> int{
51+
using zero = std::integral_constant<cpp2::i32,0>;
52+
53+
cpp2::deferred_init<zero> z;
54+
init<zero>(cpp2::out(&z));
55+
cpp2::Default.expects(&id<zero>(z.value()) == &z.value(), "");
56+
57+
// Deducible parameters.
58+
static_cast<void>(v{0});
59+
static_cast<void>([]<typename T>(std::vector<T> const& x) mutable -> void{}(std::vector<cpp2::i32>{}));
60+
static_cast<void>([]<typename T>(std::vector<std::vector<T>> const& x) mutable -> void{}(std::vector<std::vector<cpp2::i32>>{}));
61+
// _ = :<T, U> (x: std::pair<T, typename U::value_type>, y: U) = {}(:std::pair = (0, 0), z); // Blocked on #727.
62+
static_cast<void>([]<typename T, typename U>(std::array<T,U::value> const& x, U const& y) mutable -> void{}(std::array<cpp2::i32,0>{}, z.value()));
63+
init(cpp2::out(&z.value()), z.value());
64+
id(z.value(), std::move(z.value()));
65+
{
66+
auto f = []<typename T>(std::vector<std::type_identity_t<T>> const& x) mutable -> void{};
67+
68+
// Test that these are emitted unwrapped in case they are deducible.
69+
70+
#line 26 "pure2-bugfix-for-deducible-parameters.cpp2"
71+
static_assert(!(std::is_invocable_v<decltype(f),std::vector<cpp2::i32>>), "`T` is non-deducible.");
72+
}
73+
{
74+
auto f = []<typename T>(std::vector<std::vector<T>> const& x) mutable -> void{};
75+
76+
#line 28 "pure2-bugfix-for-deducible-parameters.cpp2"
77+
static_assert(std::is_invocable_v<decltype(std::move(f)),std::vector<std::vector<cpp2::i32>>>, "`T` is deducible.");
78+
}
79+
#line 29 "pure2-bugfix-for-deducible-parameters.cpp2"
80+
}
81+
82+
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2"
83+
template <typename T> v<T>::v(T const& x){}
84+
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2"
85+
template <typename T> auto v<T>::operator=(T const& x) -> v& {
86+
return *this; }
87+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-bugfix-for-deducible-parameters.cpp2... ok (all Cpp2, passes safety checks)
2+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2"
10+
11+
12+
//=== Cpp2 type definitions and function declarations ===========================
13+
14+
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2"
15+
auto main() -> int;
16+
17+
//=== Cpp2 function definitions =================================================
18+
19+
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2"
20+
auto main() -> int{
21+
#line 2 "pure2-bugfix-for-dependent-types-recursion.cpp2"
22+
using a = b;
23+
using b = a;
24+
static_cast<void>(a::t);
25+
static_cast<void>(b::t);
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-bugfix-for-dependent-types-recursion.cpp2... ok (all Cpp2, passes safety checks)
2+

0 commit comments

Comments
 (0)