Skip to content

Commit 4f399a7

Browse files
JohelEGPhsutter
andauthored
feat: add _type-id_ production for decltype (#921)
* feat: add _type-id_ production for `decltype` * Update error message and local test run results --------- Co-authored-by: Herb Sutter <[email protected]>
1 parent 54d9b9b commit 4f399a7

17 files changed

+85
-21
lines changed

regression-tests/mixed-bugfix-for-ufcs-non-local.cpp2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ d: _ == t<o.f()>(); // Fails on Clang 12 (lambda in unevaluated context).
3838

3939
u: @struct type = {
4040
b: bool == o.f();
41-
c: bool == :(x: std::type_identity_t<decltype(o.f())>) x;(true); // Fails on Clang 12 (lambda in unevaluated context).
41+
c: bool == :(x: decltype(o.f())) x;(true); // Fails on Clang 12 (lambda in unevaluated context).
4242
g: (s, sz) pre(s.sz() != 0) = { }
4343
}
4444

regression-tests/pure2-bugfix-for-non-local-function-expression.cpp2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
v: <T> concept = :() -> bool = true;();
66

7-
u: type == std::type_identity_t<decltype(:() = {})>;
7+
u: type == decltype(:() = {});
88

99
t: @struct type = {
10-
this: std::type_identity_t<decltype(:() = {})>;
10+
this: decltype(:() = {});
1111
}
1212

1313
main: () = { }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
f: () -> decltype(auto) = 0;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
x: decltype(auto) = 0;

regression-tests/pure2-last-use.cpp2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ issue_313: () = {
4242
_ = e is (e);
4343

4444
f := new<int>(0);
45-
_ = f is std::type_identity_t<decltype(f)>; // OK?
45+
_ = f is decltype(f); // OK?
4646

4747
g := new<int>(0);
4848
for (identity(g)* + identity(g)*)

regression-tests/pure2-print.cpp2

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ outer: @print type = {
100100
all: <Args...: type> (args...: Args) -> bool =
101101
(... && args);
102102

103+
y: (_: decltype(0)) = { }
104+
103105
}
104106

105107
main: () = {

regression-tests/test-results/clang-12-c++20/mixed-bugfix-for-ufcs-non-local.cpp.output

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ mixed-bugfix-for-ufcs-non-local.cpp2:27:29: error: a lambda expression cannot ap
106106
../../../include/cpp2util.h:2099:66: note: expanded from macro 'CPP2_UFCS_'
107107
#define CPP2_UFCS_(LAMBDADEFCAPT,SFINAE,MVFWD,QUALID,TEMPKW,...) \
108108
^
109-
mixed-bugfix-for-ufcs-non-local.cpp2:41:84: error: lambda expression in an unevaluated operand
110-
inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in<std::type_identity_t<decltype(CPP2_UFCS_NONLOCAL(f)(o))>> x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context).
111-
^
109+
mixed-bugfix-for-ufcs-non-local.cpp2:41:63: error: lambda expression in an unevaluated operand
110+
inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in<decltype(CPP2_UFCS_NONLOCAL(f)(o))> x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context).
111+
^
112112
../../../include/cpp2util.h:2137:59: note: expanded from macro 'CPP2_UFCS_NONLOCAL'
113113
#define CPP2_UFCS_NONLOCAL(...) CPP2_UFCS_(,CPP2_UFCS_IDENTITY,CPP2_UFCS_IDENTITY,(),,__VA_ARGS__)
114114
^
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
pure2-bugfix-for-non-local-function-expression.cpp2:5:34: error: lambda expression in an unevaluated operand
22
template<typename T> concept v = []() -> bool { return true; }();
33
^
4-
pure2-bugfix-for-non-local-function-expression.cpp2:7:41: error: lambda expression in an unevaluated operand
5-
using u = std::type_identity_t<decltype([]() -> void{})>;
6-
^
7-
pure2-bugfix-for-non-local-function-expression.cpp2:9:47: error: lambda expression in an unevaluated operand
8-
class t: public std::type_identity_t<decltype([]() -> void{})> {
9-
^
4+
pure2-bugfix-for-non-local-function-expression.cpp2:7:20: error: lambda expression in an unevaluated operand
5+
using u = decltype([]() -> void{});
6+
^
7+
pure2-bugfix-for-non-local-function-expression.cpp2:9:26: error: lambda expression in an unevaluated operand
8+
class t: public decltype([]() -> void{}) {
9+
^
1010
3 errors generated.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ auto g() -> void{
9595

9696
#line 40 "mixed-bugfix-for-ufcs-non-local.cpp2"
9797
inline CPP2_CONSTEXPR bool u::b{ CPP2_UFCS_NONLOCAL(f)(o) };
98-
inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in<std::type_identity_t<decltype(CPP2_UFCS_NONLOCAL(f)(o))>> x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context).
98+
inline CPP2_CONSTEXPR bool u::c{ [](cpp2::impl::in<decltype(CPP2_UFCS_NONLOCAL(f)(o))> x) -> auto { return x; }(true) };// Fails on Clang 12 (lambda in unevaluated context).
9999
auto u::g(auto const& s, auto const& sz) -> void{
100100
if (cpp2::cpp2_default.is_active() && !(CPP2_UFCS(sz)(s) != 0) ) { cpp2::cpp2_default.report_violation(""); }}
101101

regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ class t;
2222
#line 5 "pure2-bugfix-for-non-local-function-expression.cpp2"
2323
template<typename T> concept v = []() -> bool { return true; }();
2424

25-
using u = std::type_identity_t<decltype([]() -> void{})>;
25+
using u = decltype([]() -> void{});
2626

27-
class t: public std::type_identity_t<decltype([]() -> void{})> {
27+
class t: public decltype([]() -> void{}) {
2828

2929
};
3030

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pure2-deduction-1-error.cpp2...
2+
pure2-deduction-1-error.cpp2(1,10): error: decltype(auto) is not needed in Cpp2 - for return types, use '-> forward _' instead
3+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pure2-deduction-2-error.cpp2...
2+
pure2-deduction-2-error.cpp2(1,4): error: decltype(auto) is not needed in Cpp2 - for return types, use '-> forward _' instead
3+

regression-tests/test-results/pure2-last-use.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ auto issue_313() -> void{
606606
static_cast<void>(cpp2::impl::is(e, (e)));
607607

608608
auto f {cpp2_new<int>(0)};
609-
static_cast<void>(cpp2::impl::is<std::type_identity_t<decltype(f)>>(f));// OK?
609+
static_cast<void>(cpp2::impl::is<decltype(f)>(f));// OK?
610610

611611
auto g {cpp2_new<int>(0)};
612612
for (

regression-tests/test-results/pure2-print.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,15 @@ CPP2_REQUIRES_ (cpp2::impl::cmp_greater_eq(sizeof...(Args),0u)) ;
7070

7171
#line 100 "pure2-print.cpp2"
7272
public: template<typename ...Args> [[nodiscard]] static auto all(Args const& ...args) -> bool;
73+
74+
#line 103 "pure2-print.cpp2"
75+
public: static auto y([[maybe_unused]] cpp2::impl::in<decltype(0)> unnamed_param_1) -> void;
7376
public: outer() = default;
7477
public: outer(outer const&) = delete; /* No 'that' constructor, suppress copy */
7578
public: auto operator=(outer const&) -> void = delete;
7679

7780

78-
#line 103 "pure2-print.cpp2"
81+
#line 105 "pure2-print.cpp2"
7982
};
8083

8184
auto main() -> int;
@@ -199,7 +202,10 @@ requires (cpp2::impl::cmp_greater_eq(sizeof...(Args),0u)) {
199202
template<typename ...Args> [[nodiscard]] auto outer::all(Args const& ...args) -> bool {
200203
return (... && args); }
201204

202-
#line 105 "pure2-print.cpp2"
205+
#line 103 "pure2-print.cpp2"
206+
auto outer::y([[maybe_unused]] cpp2::impl::in<decltype(0)> unnamed_param_1) -> void{}
207+
208+
#line 107 "pure2-print.cpp2"
203209
auto main() -> int{
204210
outer::test();
205211
}

regression-tests/test-results/pure2-print.cpp2.output

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ outer:/* @print */ type =
146146
}
147147

148148
all: <Args...: type, >(in args...: Args, ) -> move bool = (... && args);
149+
150+
y:(in _: decltype(0), ) =
151+
{
152+
}
149153
}
150154
ok (all Cpp2, passes safety checks)
151155

source/parse.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,9 +1369,10 @@ struct type_id_node
13691369
int dereference_cnt = {};
13701370
token const* suspicious_initialization = {};
13711371

1372-
enum active : u8 { empty=0, qualified, unqualified, function, keyword };
1372+
enum active : u8 { empty=0, decltype_, qualified, unqualified, function, keyword };
13731373
std::variant<
13741374
std::monostate,
1375+
std::unique_ptr<postfix_expression_node>,
13751376
std::unique_ptr<qualified_id_node>,
13761377
std::unique_ptr<unqualified_id_node>,
13771378
std::unique_ptr<function_type_node>,
@@ -1423,6 +1424,9 @@ struct type_id_node
14231424
if (id.index() == unqualified) {
14241425
return std::get<unqualified>(id)->template_arguments();
14251426
}
1427+
else if (id.index() != qualified) {
1428+
cpp2_default.report_violation("ICE: this type_id has no template arguments");
1429+
}
14261430
// else
14271431
return std::get<qualified>(id)->template_arguments();
14281432
}
@@ -1436,6 +1440,8 @@ struct type_id_node
14361440
switch (id.index()) {
14371441
break;case empty:
14381442
return {};
1443+
break;case decltype_:
1444+
return {};
14391445
break;case qualified:
14401446
return {};
14411447
break;case unqualified:
@@ -1464,6 +1470,7 @@ struct type_id_node
14641470
for (auto q : pc_qualifiers) {
14651471
v.start(*q, depth+1);
14661472
}
1473+
try_visit<decltype_ >(id, v, depth);
14671474
try_visit<qualified >(id, v, depth);
14681475
try_visit<unqualified>(id, v, depth);
14691476
try_visit<function >(id, v, depth);
@@ -2779,6 +2786,8 @@ auto type_id_node::to_string() const
27792786
switch (id.index()) {
27802787
break;case empty:
27812788
ret += "_";
2789+
break;case decltype_:
2790+
ret += std::get<decltype_>(id)->to_string();
27822791
break;case qualified:
27832792
ret += std::get<qualified>(id)->to_string();
27842793
break;case unqualified:
@@ -5102,6 +5111,7 @@ auto pretty_print_visualize(type_id_node const& n, int indent)
51025111
}
51035112

51045113
if (n.id.index() == type_id_node::empty) { ret += "_"; }
5114+
ret += try_pretty_print_visualize<type_id_node::decltype_ >(n.id, indent);
51055115
ret += try_pretty_print_visualize<type_id_node::qualified >(n.id, indent);
51065116
ret += try_pretty_print_visualize<type_id_node::unqualified>(n.id, indent);
51075117
ret += try_pretty_print_visualize<type_id_node::function >(n.id, indent);
@@ -6885,6 +6895,7 @@ class parser
68856895

68866896

68876897
//G type-id:
6898+
//G type-qualifier-seq? 'decltype' '(' expression ')' is-type-constraint?
68886899
//G type-qualifier-seq? qualified-id is-type-constraint?
68896900
//G type-qualifier-seq? unqualified-id is-type-constraint?
68906901
//G type-qualifier-seq? function-type is-type-constraint?
@@ -6927,7 +6938,39 @@ class parser
69276938
next();
69286939
}
69296940

6930-
if (auto id = qualified_id()) {
6941+
if (auto& c = curr();
6942+
c == "decltype"
6943+
)
6944+
{
6945+
if (
6946+
peek(1) && peek(1)->type() == lexeme::LeftParen
6947+
&& peek(2) && *peek(2) == "auto"
6948+
&& peek(3) && peek(3)->type() == lexeme::RightParen)
6949+
{
6950+
error(
6951+
"decltype(auto) is not needed in Cpp2 - for return types, use '-> forward _' instead",
6952+
false,
6953+
c.position()
6954+
);
6955+
}
6956+
if (auto id = postfix_expression();
6957+
id
6958+
&& id->ops.size() == 1
6959+
&& id->ops[0].expr_list->expressions.size() == 1
6960+
&& id->ops[0].expr_list->open_paren->type() == lexeme::LeftParen
6961+
)
6962+
{
6963+
n->pos = id->position();
6964+
n->id = std::move(id);
6965+
assert (n->id.index() == type_id_node::decltype_);
6966+
}
6967+
else
6968+
{
6969+
error("'decltype' must be followed by a single parenthesized expression", false, c.position());
6970+
return {};
6971+
}
6972+
}
6973+
else if (auto id = qualified_id()) {
69316974
n->pos = id->position();
69326975
n->id = std::move(id);
69336976
assert (n->id.index() == type_id_node::qualified);

source/to_cpp1.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,6 +1939,7 @@ class cppfront
19391939
printer.print_cpp2("auto", pos);
19401940
}
19411941
else {
1942+
try_emit<type_id_node::decltype_ >(n.id);
19421943
try_emit<type_id_node::unqualified>(n.id, 0, false);
19431944
try_emit<type_id_node::qualified >(n.id);
19441945
try_emit<type_id_node::keyword >(n.id);

0 commit comments

Comments
 (0)