Skip to content

Commit 44a357b

Browse files
committed
refactor: workaround MSVC bogus error C3537
`error C3537: you cannot cast to a type that contains 'auto'`. See <https://compiler-explorer.com/z/Tfbj795s3> not working and <https://compiler-explorer.com/z/31osnhrGo> working.
1 parent 4571e1d commit 44a357b

File tree

2 files changed

+64
-59
lines changed

2 files changed

+64
-59
lines changed

regression-tests/test-results/pure2-function-type-id.cpp

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,26 @@ auto main() -> int;
1616

1717
#line 80 "pure2-function-type-id.cpp2"
1818
// As non-local function parameter.
19-
auto g(cpp2::in<cpp2::fn_t<auto () -> void>> f) -> void;
20-
auto g(cpp2::fn_t<auto () -> void>* f) -> void;
21-
auto g(cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>* f) -> void;
19+
auto g(cpp2::in<cpp2::fn_t<void()>> f) -> void;
20+
auto g(cpp2::fn_t<void()>* f) -> void;
21+
auto g(cpp2::fn_t<cpp2::fn_t<void()>*()>* f) -> void;
2222
// As template parameter.
23-
template<cpp2::fn_t<auto () -> void>* V> auto g() -> void;
24-
template<cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>* V> auto g() -> void;
23+
template<cpp2::fn_t<void()>* V> auto g() -> void;
24+
template<cpp2::fn_t<cpp2::fn_t<void()>*()>* V> auto g() -> void;
2525

2626
// In non-local function return type.
27-
[[nodiscard]] auto g1() -> cpp2::fn_t<auto () -> void>*;
28-
template<bool V> [[nodiscard]] auto g1() -> cpp2::fn_t<auto () -> void>*;
29-
[[nodiscard]] auto g2() -> cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>*;
27+
[[nodiscard]] auto g1() -> cpp2::fn_t<void()>*;
28+
template<bool V> [[nodiscard]] auto g1() -> cpp2::fn_t<void()>*;
29+
[[nodiscard]] auto g2() -> cpp2::fn_t<cpp2::fn_t<void()>*()>*;
3030

3131
// clang-format off
3232
// Test case from #343.
33-
[[nodiscard]] auto f2() -> std::function<cpp2::fn_t<auto (cpp2::in<std::string>) -> std::string>>;
33+
[[nodiscard]] auto f2() -> std::function<cpp2::fn_t<std::string(cpp2::in<std::string>)>>;
3434

3535

3636
#line 99 "pure2-function-type-id.cpp2"
3737
// Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>.
38-
[[nodiscard]] auto f(cpp2::in<cpp2::i32> x) -> cpp2::fn_t<auto (cpp2::in<cpp2::i32>) -> std::string>*;
38+
[[nodiscard]] auto f(cpp2::in<cpp2::i32> x) -> cpp2::fn_t<std::string(cpp2::in<cpp2::i32>)>*;
3939
auto postfix_operators() -> void;
4040

4141

@@ -46,19 +46,19 @@ auto main() -> int{
4646
postfix_operators();
4747

4848
// Variables with type of a mix of `*`/`const` to `() throws -> void`.
49-
cpp2::fn_t<auto () -> void>* f0 {[]() -> void{}};
50-
cpp2::fn_t<auto () -> void>* const f1 {f0};
51-
cpp2::fn_t<auto () -> void> const* f2 {f0};
52-
cpp2::fn_t<auto () -> void> const* const f3 {f0};
49+
cpp2::fn_t<void()>* f0 {[]() -> void{}};
50+
cpp2::fn_t<void()>* const f1 {f0};
51+
cpp2::fn_t<void()> const* f2 {f0};
52+
cpp2::fn_t<void()> const* const f3 {f0};
5353

5454
// Uninitialized.
55-
cpp2::deferred_init<cpp2::fn_t<auto () -> void>*> f4;
55+
cpp2::deferred_init<cpp2::fn_t<void()>*> f4;
5656
f4.construct(f0);
5757

58-
cpp2::fn_t<auto () -> void>** f10 {&f0};
59-
cpp2::fn_t<auto () -> void>** const f11 {f10};
60-
cpp2::fn_t<auto () -> void>* const* f12 {f10};
61-
cpp2::fn_t<auto () -> void>* const* const f13 {f10};
58+
cpp2::fn_t<void()>** f10 {&f0};
59+
cpp2::fn_t<void()>** const f11 {f10};
60+
cpp2::fn_t<void()>* const* f12 {f10};
61+
cpp2::fn_t<void()>* const* const f13 {f10};
6262

6363
cpp2::i32 i {0};
6464
cpp2::i32* i0 {&i};
@@ -81,86 +81,86 @@ auto main() -> int{
8181
(void) std::move(i3);
8282

8383
// Variables with various kinds of parameter.
84-
cpp2::fn_t<auto (cpp2::in<cpp2::i32>) -> void>* f5 {[](cpp2::in<cpp2::i32> x) -> void{}};
85-
cpp2::fn_t<auto (cpp2::in<std::any>) -> void>* f6 {[](cpp2::in<std::any> x) -> void{}};
86-
cpp2::fn_t<auto (cpp2::i32&&) -> void>* f7 {[](cpp2::i32&& x) -> void{}};
87-
cpp2::fn_t<auto (cpp2::out<cpp2::i32>) -> void>* f8 {[](auto x) -> void{}};
84+
cpp2::fn_t<void(cpp2::in<cpp2::i32>)>* f5 {[](cpp2::in<cpp2::i32> x) -> void{}};
85+
cpp2::fn_t<void(cpp2::in<std::any>)>* f6 {[](cpp2::in<std::any> x) -> void{}};
86+
cpp2::fn_t<void(cpp2::i32&&)>* f7 {[](cpp2::i32&& x) -> void{}};
87+
cpp2::fn_t<void(cpp2::out<cpp2::i32>)>* f8 {[](auto x) -> void{}};
8888

8989
// In alternative.
9090
cpp2::Default.expects([&] () -> bool { auto&& __expr = f0;
91-
if (cpp2::is<cpp2::fn_t<auto () noexcept -> void>>(__expr)) { if constexpr( requires{std::terminate(), false;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::terminate(), false)),bool> ) return std::terminate(), false; else return bool{}; else return bool{}; }
92-
else if (cpp2::is<cpp2::fn_t<auto () -> void>>(__expr)) { if constexpr( requires{std::terminate(), false;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::terminate(), false)),bool> ) return std::terminate(), false; else return bool{}; else return bool{}; }
93-
else if (cpp2::is<cpp2::fn_t<auto () -> void>*>(__expr)) { if constexpr( requires{true;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((true)),bool> ) return true; else return bool{}; else return bool{}; }
91+
if (cpp2::is<cpp2::fn_t<void() noexcept>>(__expr)) { if constexpr( requires{std::terminate(), false;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::terminate(), false)),bool> ) return std::terminate(), false; else return bool{}; else return bool{}; }
92+
else if (cpp2::is<cpp2::fn_t<void()>>(__expr)) { if constexpr( requires{std::terminate(), false;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((std::terminate(), false)),bool> ) return std::terminate(), false; else return bool{}; else return bool{}; }
93+
else if (cpp2::is<cpp2::fn_t<void()>*>(__expr)) { if constexpr( requires{true;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((true)),bool> ) return true; else return bool{}; else return bool{}; }
9494
else return false; }
9595
(), "");
9696
cpp2::Default.expects([&] () -> bool { auto&& __expr = *cpp2::assert_not_null(f0);
97-
if (cpp2::is<cpp2::fn_t<auto () -> void>>(__expr)) { if constexpr( requires{true;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((true)),bool> ) return true; else return bool{}; else return bool{}; }
97+
if (cpp2::is<cpp2::fn_t<void()>>(__expr)) { if constexpr( requires{true;} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF((true)),bool> ) return true; else return bool{}; else return bool{}; }
9898
else return false; }
9999
(), "");
100100
{
101-
cpp2::fn_t<auto () -> void>* f = f0;
101+
cpp2::fn_t<void()>* f = f0;
102102

103103
// As block variable.
104104
#line 58 "pure2-function-type-id.cpp2"
105105
{}
106106
}
107107
{
108-
cpp2::in<cpp2::fn_t<auto () -> void>> f = *cpp2::assert_not_null(f0);
108+
cpp2::in<cpp2::fn_t<void()>> f = *cpp2::assert_not_null(f0);
109109
#line 59 "pure2-function-type-id.cpp2"
110110
{ }
111111
}
112112

113113
// As local function parameter.
114114
#line 62 "pure2-function-type-id.cpp2"
115-
(void) [](cpp2::in<cpp2::fn_t<auto () -> void>> f) -> void{};
116-
(void) [](cpp2::fn_t<auto () -> void>* f) -> void{};
117-
(void) [](cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>* f) -> void{};
118-
(void) [](cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>*>* f) -> void{};
115+
(void) [](cpp2::in<cpp2::fn_t<void()>> f) -> void{};
116+
(void) [](cpp2::fn_t<void()>* f) -> void{};
117+
(void) [](cpp2::fn_t<cpp2::fn_t<void()>*()>* f) -> void{};
118+
(void) [](cpp2::fn_t<cpp2::fn_t<cpp2::fn_t<void()>*()>*()>* f) -> void{};
119119

120120
// In local function return type.
121-
(void) [_0 = f0]() -> cpp2::fn_t<auto () -> void>& { return *cpp2::assert_not_null(_0); };
122-
(void) []() -> cpp2::fn_t<auto () -> void>* { return nullptr; };
123-
(void) []() -> cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>* { return nullptr; };
121+
(void) [_0 = f0]() -> cpp2::fn_t<void()>& { return *cpp2::assert_not_null(_0); };
122+
(void) []() -> cpp2::fn_t<void()>* { return nullptr; };
123+
(void) []() -> cpp2::fn_t<cpp2::fn_t<void()>*()>* { return nullptr; };
124124

125125
// Without `throws`.
126-
(void) std::type_identity_t<cpp2::fn_t<auto (std::string_view, CPP2_MESSAGE_PARAM) noexcept -> void>*>{cpp2::report_and_terminate};
126+
(void) std::type_identity_t<cpp2::fn_t<void(std::string_view, CPP2_MESSAGE_PARAM) noexcept>*>{cpp2::report_and_terminate};
127127

128128
// As template argument.
129-
(void) std::type_identity_t<cpp2::fn_t<auto () -> void>*>{std::move(f0)};
130-
static_assert(std::is_function_v<cpp2::fn_t<auto () -> void>>);
129+
(void) std::type_identity_t<cpp2::fn_t<void()>*>{std::move(f0)};
130+
static_assert(std::is_function_v<cpp2::fn_t<void()>>);
131131
}
132132

133133
#line 81 "pure2-function-type-id.cpp2"
134-
auto g(cpp2::in<cpp2::fn_t<auto () -> void>> f) -> void{}
135-
auto g(cpp2::fn_t<auto () -> void>* f) -> void{}
136-
auto g(cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>* f) -> void{}
134+
auto g(cpp2::in<cpp2::fn_t<void()>> f) -> void{}
135+
auto g(cpp2::fn_t<void()>* f) -> void{}
136+
auto g(cpp2::fn_t<cpp2::fn_t<void()>*()>* f) -> void{}
137137

138-
template<cpp2::fn_t<auto () -> void>* V> auto g() -> void{}
139-
template<cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>* V> auto g() -> void{}
138+
template<cpp2::fn_t<void()>* V> auto g() -> void{}
139+
template<cpp2::fn_t<cpp2::fn_t<void()>*()>* V> auto g() -> void{}
140140

141141
#line 89 "pure2-function-type-id.cpp2"
142-
[[nodiscard]] auto g1() -> cpp2::fn_t<auto () -> void>* { return nullptr; }
143-
template<bool V> [[nodiscard]] auto g1() -> cpp2::fn_t<auto () -> void>*
142+
[[nodiscard]] auto g1() -> cpp2::fn_t<void()>* { return nullptr; }
143+
template<bool V> [[nodiscard]] auto g1() -> cpp2::fn_t<void()>*
144144
requires (V)
145145
#line 90 "pure2-function-type-id.cpp2"
146146
{return nullptr; }
147-
[[nodiscard]] auto g2() -> cpp2::fn_t<auto () -> cpp2::fn_t<auto () -> void>*>* { return nullptr; }
147+
[[nodiscard]] auto g2() -> cpp2::fn_t<cpp2::fn_t<void()>*()>* { return nullptr; }
148148

149149
#line 95 "pure2-function-type-id.cpp2"
150-
[[nodiscard]] auto f2() -> std::function<cpp2::fn_t<auto (cpp2::in<std::string>) -> std::string>>{
150+
[[nodiscard]] auto f2() -> std::function<cpp2::fn_t<std::string(cpp2::in<std::string>)>>{
151151
return [](cpp2::in<std::string> s) -> std::string{return s + " World!"; };
152152
}
153153

154154
#line 100 "pure2-function-type-id.cpp2"
155-
[[nodiscard]] auto f(cpp2::in<cpp2::i32> x) -> cpp2::fn_t<auto (cpp2::in<cpp2::i32>) -> std::string>* { return +[](cpp2::in<cpp2::i32> x) -> std::string { return ""; }; }
155+
[[nodiscard]] auto f(cpp2::in<cpp2::i32> x) -> cpp2::fn_t<std::string(cpp2::in<cpp2::i32>)>* { return +[](cpp2::in<cpp2::i32> x) -> std::string { return ""; }; }
156156
auto postfix_operators() -> void{
157-
cpp2::Default.expects(cpp2::is<cpp2::fn_t<auto (cpp2::in<cpp2::i32>) -> cpp2::fn_t<auto (cpp2::in<cpp2::i32>) -> std::string>*>>(f), "");
157+
cpp2::Default.expects(cpp2::is<cpp2::fn_t<cpp2::fn_t<std::string(cpp2::in<cpp2::i32>)>*(cpp2::in<cpp2::i32>)>>(f), "");
158158
// / | |
159159
// / | |
160-
cpp2::Default.expects(cpp2::is<cpp2::fn_t<auto (cpp2::in<cpp2::i32>) -> std::string>*>(f(42)), "");
160+
cpp2::Default.expects(cpp2::is<cpp2::fn_t<std::string(cpp2::in<cpp2::i32>)>*>(f(42)), "");
161161
// ________________/ |
162162
// / |
163-
cpp2::Default.expects(cpp2::is<cpp2::fn_t<auto (cpp2::in<cpp2::i32>) -> std::string>>(*cpp2::assert_not_null(f(42))), "");
163+
cpp2::Default.expects(cpp2::is<cpp2::fn_t<std::string(cpp2::in<cpp2::i32>)>>(*cpp2::assert_not_null(f(42))), "");
164164
// _______________/
165165
// /
166166
cpp2::Default.expects(cpp2::is<std::string>((*cpp2::assert_not_null(f(42)))(1)), "");

source/cppfront.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,6 +4261,11 @@ class cppfront
42614261
)
42624262
-> void
42634263
{
4264+
auto return_type_introducer = std::string{" -> "};
4265+
if (is_function_type_id) {
4266+
return_type_introducer.clear();
4267+
}
4268+
42644269
// Handle a special member function
42654270
if (
42664271
!is_function_type_id
@@ -4274,7 +4279,7 @@ class cppfront
42744279
&& n.my_decl->parent_declaration->name()
42754280
);
42764281
printer.print_cpp2(
4277-
" -> " + print_to_string( *n.my_decl->parent_declaration->name() ) + "& ",
4282+
return_type_introducer + print_to_string( *n.my_decl->parent_declaration->name() ) + "& ",
42784283
n.position()
42794284
);
42804285
}
@@ -4284,11 +4289,11 @@ class cppfront
42844289
{
42854290
if (is_main)
42864291
{
4287-
printer.print_cpp2( " -> int", n.position() );
4292+
printer.print_cpp2( return_type_introducer + "int", n.position() );
42884293
}
42894294
else if(!is_ctor_or_dtor)
42904295
{
4291-
printer.print_cpp2( " -> void", n.position() );
4296+
printer.print_cpp2( return_type_introducer + "void", n.position() );
42924297
}
42934298
}
42944299

@@ -4302,7 +4307,7 @@ class cppfront
43024307
&& (*n.parameters)[0]->direction() == passing_style::in
43034308
;
43044309

4305-
printer.print_cpp2( " -> ", n.position() );
4310+
printer.print_cpp2( return_type_introducer, n.position() );
43064311
auto& r = std::get<function_type_node::id>(n.returns);
43074312
assert(r.type);
43084313
if (r.pass == passing_style::forward) {
@@ -4326,7 +4331,7 @@ class cppfront
43264331

43274332
// Otherwise, handle multiple/named returns
43284333
else {
4329-
printer.print_cpp2( " -> ", n.position() );
4334+
printer.print_cpp2( return_type_introducer, n.position() );
43304335
function_return_name = {};
43314336
printer.emit_to_string(&function_return_name);
43324337
assert(ident);
@@ -4341,12 +4346,12 @@ class cppfront
43414346
-> void
43424347
{
43434348
assert(n.type);
4344-
printer.print_cpp2( "cpp2::fn_t<auto ", n.type->position() );
4349+
printer.print_cpp2( "cpp2::fn_t<", n.type->position() );
4350+
emit(*n.type, function_returns_tag{}, nullptr, false, false, true);
43454351
emit(*n.type->parameters, false, false, true);
43464352
if (!n.type->throws) {
43474353
printer.print_cpp2( " noexcept", n.type->position() );
43484354
}
4349-
emit(*n.type, function_returns_tag{}, nullptr, false, false, true);
43504355
printer.print_cpp2( ">", n.type->position() );
43514356
}
43524357

0 commit comments

Comments
 (0)