Skip to content

Commit 55710ba

Browse files
committed
fix(to_cpp1): emit qualified UFCS template call correctly
1 parent 0c8fa21 commit 55710ba

File tree

4 files changed

+54
-19
lines changed

4 files changed

+54
-19
lines changed

include/cpp2util.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -785,17 +785,19 @@ class out {
785785
#endif
786786
#endif
787787

788+
#define CPP2_UFCS_REMPARENS(...) __VA_ARGS__
789+
788790
// Ideally, the expression `CPP2_UFCS_IS_NOTHROW` expands to
789791
// is in the _noexcept-specifier_ of the UFCS lambda.
790792
// To workaround [GCC bug 101043](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101043),
791793
// we instead make it a template parameter of the UFCS lambda.
792794
// But using a template parameter, Clang also ICEs on an application.
793795
// So we use these `NOTHROW` macros to fall back to the ideal for when not using GCC.
794796
#define CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,...) \
795-
requires { requires requires { std::declval<Obj>().QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); }; \
796-
requires noexcept(std::declval<Obj>().QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...)); } \
797-
|| requires { requires !requires { std::declval<Obj>().QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); }; \
798-
requires noexcept(QUALID __VA_ARGS__(std::declval<Obj>(), std::declval<Params>()...)); }
797+
requires { requires requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); }; \
798+
requires noexcept(std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...)); } \
799+
|| requires { requires !requires { std::declval<Obj>().CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(std::declval<Params>()...); }; \
800+
requires noexcept(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(std::declval<Obj>(), std::declval<Params>()...)); }
799801
#define CPP2_UFCS_IS_NOTHROW_PARAM(QUALID,TEMPKW,...) /*empty*/
800802
#define CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,...) CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,__VA_ARGS__)
801803
#if defined(__GNUC__) && !defined(__clang__)
@@ -815,20 +817,20 @@ class out {
815817
[LAMBDADEFCAPT]<typename Obj, typename... Params CPP2_UFCS_IS_NOTHROW_PARAM(QUALID,TEMPKW,__VA_ARGS__)> \
816818
CPP2_LAMBDA_NO_DISCARD (Obj&& obj, Params&& ...params) CPP2_FORCE_INLINE_LAMBDA_CLANG \
817819
noexcept(CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,__VA_ARGS__)) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) \
818-
requires requires { CPP2_FORWARD(obj).QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); } \
819-
|| requires { QUALID __VA_ARGS__(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); } { \
820-
if constexpr (requires{ CPP2_FORWARD(obj).QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); }) { \
821-
return CPP2_FORWARD(obj).QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \
820+
requires requires { CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); } \
821+
|| requires { CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); } { \
822+
if constexpr (requires{ CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); }) { \
823+
return CPP2_FORWARD(obj).CPP2_UFCS_REMPARENS QUALID TEMPKW __VA_ARGS__(CPP2_FORWARD(params)...); \
822824
} else { \
823-
return QUALID __VA_ARGS__(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \
825+
return CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(CPP2_FORWARD(obj), CPP2_FORWARD(params)...); \
824826
} \
825827
}
826828

827-
#define CPP2_UFCS(...) CPP2_UFCS_(&,,,__VA_ARGS__)
828-
#define CPP2_UFCS_TEMPLATE(...) CPP2_UFCS_(&,,template,__VA_ARGS__)
829+
#define CPP2_UFCS(...) CPP2_UFCS_(&,(),,__VA_ARGS__)
830+
#define CPP2_UFCS_TEMPLATE(...) CPP2_UFCS_(&,(),template,__VA_ARGS__)
829831
#define CPP2_UFCS_QUALIFIED_TEMPLATE(QUALID,...) CPP2_UFCS_(&,QUALID,template,__VA_ARGS__)
830-
#define CPP2_UFCS_NONLOCAL(...) CPP2_UFCS_(,,,__VA_ARGS__)
831-
#define CPP2_UFCS_TEMPLATE_NONLOCAL(...) CPP2_UFCS_(,,template,__VA_ARGS__)
832+
#define CPP2_UFCS_NONLOCAL(...) CPP2_UFCS_(,(),,__VA_ARGS__)
833+
#define CPP2_UFCS_TEMPLATE_NONLOCAL(...) CPP2_UFCS_(,(),template,__VA_ARGS__)
832834
#define CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL(QUALID,...) CPP2_UFCS_(,QUALID,template,__VA_ARGS__)
833835

834836

regression-tests/pure2-bugfix-for-ufcs-arguments.cpp2

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ main: () = {
4949

5050
_ = :(a, f) = { _ = a.f(a).f(); };
5151
_ = 0.std::min<int>(0);
52+
_ = 0.ns::t<0, 0>::f<0>();
5253
}
5354

5455
_: i32 = 0.std::min<int>(0);
56+
_: i32 = 0.ns::t<0, 0>::f<0>();
57+
58+
ns: namespace = {
59+
t: @struct <T: int, U: int> type = {
60+
f: <V: int> (_: int) -> i32 = 0;
61+
}
62+
} // namespace ns

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
class t;
1313

1414

15+
#line 58 "pure2-bugfix-for-ufcs-arguments.cpp2"
16+
namespace ns {
17+
template<int T, int U> class t;
18+
19+
20+
}
21+
22+
1523
//=== Cpp2 type definitions and function declarations ===========================
1624

1725
#line 1 "pure2-bugfix-for-ufcs-arguments.cpp2"
@@ -50,8 +58,16 @@ extern cpp2::i32 auto_35_1;
5058

5159
auto main() -> int;
5260

53-
#line 54 "pure2-bugfix-for-ufcs-arguments.cpp2"
54-
extern cpp2::i32 auto_54_1;
61+
#line 55 "pure2-bugfix-for-ufcs-arguments.cpp2"
62+
extern cpp2::i32 auto_55_1;
63+
extern cpp2::i32 auto_56_1;
64+
65+
namespace ns {
66+
template<int T, int U> class t {
67+
public: template<int V> [[nodiscard]] static auto f([[maybe_unused]] cpp2::in<int> unnamed_param_1) -> cpp2::i32;
68+
};
69+
} // namespace ns
70+
5571

5672
//=== Cpp2 function definitions =================================================
5773

@@ -107,8 +123,16 @@ auto main() -> int{
107123
static_cast<void>(CPP2_UFCS_TEMPLATE(f<t,t>)(a<t,t>, 0, 0));
108124

109125
static_cast<void>([](auto const& a, auto const& f) -> void{static_cast<void>(CPP2_UFCS(f)(CPP2_UFCS(f)(a, a))); });
110-
static_cast<void>(CPP2_UFCS_QUALIFIED_TEMPLATE(std::,min<int>)(0, 0));
126+
static_cast<void>(CPP2_UFCS_QUALIFIED_TEMPLATE((std::),min<int>)(0, 0));
127+
static_cast<void>(CPP2_UFCS_QUALIFIED_TEMPLATE((ns::t<0,0>::),f<0>)(0));
111128
}
112129

113-
cpp2::i32 auto_54_1 {CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL(std::,min<int>)(0, 0)};
130+
cpp2::i32 auto_55_1 {CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL((std::),min<int>)(0, 0)};
131+
cpp2::i32 auto_56_1 {CPP2_UFCS_QUALIFIED_TEMPLATE_NONLOCAL((ns::t<0,0>::),f<0>)(0)};
132+
133+
namespace ns {
134+
135+
template <int T, int U> template<int V> [[nodiscard]] auto t<T,U>::f([[maybe_unused]] cpp2::in<int> unnamed_param_1) -> cpp2::i32 { return 0; }
136+
137+
}
114138

source/to_cpp1.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3157,8 +3157,9 @@ class cppfront
31573157
// And split the unqualified id in the function name as two macro arguments
31583158
auto& id = *get<id_expression_node::qualified>(i->id_expr->id);
31593159
funcname =
3160-
print_to_string(id, false)
3161-
+ "::,"
3160+
"("
3161+
+ print_to_string(id, false)
3162+
+ "::),"
31623163
+ print_to_string(*cpp2::assert_not_null(id.ids.back().id), false, true, true);
31633164
}
31643165
ufcs_string += "_TEMPLATE";

0 commit comments

Comments
 (0)