Skip to content

Commit 88d0fa2

Browse files
committed
fix(cpp1): define static data member in the class body if possible
1 parent 083c8a0 commit 88d0fa2

5 files changed

+116
-16
lines changed

regression-tests/pure2-type-and-namespace-aliases.cpp2

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,25 @@ main: () = {
3333
myfunc2 :== myfunc;
3434
myfunc2();
3535
}
36+
37+
myclass5: type == myclass4;
38+
39+
myclass3: @struct type = {
40+
v0 :== :std::array = (0);;
41+
v1: std::array == v0;
42+
v2: myclass3 == :myclass3 = ();;
43+
v3: _ == v0;
44+
// v4 :== v2; // Not (yet) supported.
45+
// v5: myclass4 == :myclass4 = ();; // Not yet supported.
46+
// v6: myclass5 == :myclass5 = ();; // Not yet supported.
47+
// v7 :== myclass3(); // Not (yet) supported.
48+
49+
// There's also a false positive:
50+
// <https://github.com/hsutter/cppfront/issues/666#issuecomment-1722329609>.
51+
}
52+
53+
myclass4: @struct type = { }
54+
55+
myclass6: @struct <T: type> type = {
56+
v: <U> _ requires true == 0;
57+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
pure2-bugfix-for-non-local-function-expression.cpp2:9:7: warning: ‘t’ has a base ‘t::<lambda()>’ which has no linkage [-Wsubobject-linkage]
2+
9 | t: @struct type = {
3+
| ^

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class outer {
2222
public: template<typename T>
2323
CPP2_REQUIRES_ (true)
2424
#line 6 "pure2-print.cpp2"
25-
static const T object_alias;
25+
static constexpr T object_alias = 42;
2626

2727
public: class mytype final
2828
{
@@ -90,12 +90,6 @@ auto main() -> int;
9090
//=== Cpp2 function definitions =================================================
9191

9292

93-
#line 6 "pure2-print.cpp2"
94-
template<typename T>
95-
requires (true)
96-
#line 6 "pure2-print.cpp2"
97-
inline CPP2_CONSTEXPR T outer::object_alias = 42;
98-
9993
#line 10 "pure2-print.cpp2"
10094
[[nodiscard]] auto outer::mytype::f() -> int { return 42; }
10195

regression-tests/test-results/pure2-type-and-namespace-aliases.cpp

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ class myclass;
2020
template<typename T> class myclass2;
2121

2222

23+
#line 39 "pure2-type-and-namespace-aliases.cpp2"
24+
class myclass3;
25+
26+
27+
#line 53 "pure2-type-and-namespace-aliases.cpp2"
28+
class myclass4;
29+
30+
template<typename T> class myclass6;
31+
32+
2333
//=== Cpp2 type definitions and function declarations ===========================
2434

2535

@@ -49,7 +59,7 @@ auto myfunc() -> void;
4959

5060
#line 25 "pure2-type-and-namespace-aliases.cpp2"
5161
template<typename T> class myclass2 {
52-
public: static const int value;
62+
public: static constexpr int value = 42;
5363

5464
public: myclass2() = default;
5565
public: myclass2(myclass2 const&) = delete; /* No 'that' constructor, suppress copy */
@@ -60,6 +70,33 @@ template<typename T> class myclass2 {
6070
auto main() -> int;
6171

6272

73+
#line 37 "pure2-type-and-namespace-aliases.cpp2"
74+
using myclass5 = myclass4;
75+
76+
class myclass3 {
77+
public: static constexpr auto v0 = std::array{0};
78+
public: static constexpr std::array v1 = v0;
79+
public: static const myclass3 v2;
80+
public: static constexpr auto v3 = v0;
81+
// v4 :== v2; // Not (yet) supported.
82+
// v5: myclass4 == :myclass4 = ();; // Not yet supported.
83+
// v6: myclass5 == :myclass5 = ();; // Not yet supported.
84+
// v7 :== myclass3(); // Not (yet) supported.
85+
86+
// There's also a false positive:
87+
// <https://github.com/hsutter/cppfront/issues/666#issuecomment-1722329609>.
88+
};
89+
90+
class myclass4 {};
91+
92+
template<typename T> class myclass6 {
93+
public: template<typename U>
94+
CPP2_REQUIRES_ (true)
95+
#line 56 "pure2-type-and-namespace-aliases.cpp2"
96+
static constexpr auto v = 0;
97+
};
98+
99+
63100
//=== Cpp2 function definitions =================================================
64101

65102

@@ -81,9 +118,6 @@ auto const& v2 = std::move(v);
81118
#line 23 "pure2-type-and-namespace-aliases.cpp2"
82119
}
83120

84-
#line 26 "pure2-type-and-namespace-aliases.cpp2"
85-
template <typename T> inline CPP2_CONSTEXPR int myclass2<T>::value = 42;
86-
87121
#line 29 "pure2-type-and-namespace-aliases.cpp2"
88122
auto main() -> int{
89123
using view = std::string_view;
@@ -93,3 +127,7 @@ auto main() -> int{
93127
myfunc2();
94128
}
95129

130+
#line 42 "pure2-type-and-namespace-aliases.cpp2"
131+
inline CPP2_CONSTEXPR myclass3 myclass3::v2 = myclass3{};
132+
133+

source/cppfront.cpp

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4958,6 +4958,25 @@ class cppfront
49584958
}
49594959

49604960

4961+
auto has_potentially_incomplete_type(
4962+
declaration_node const& n,
4963+
type_id_node const& t
4964+
)
4965+
-> bool
4966+
{
4967+
auto type_id = t.get_token();
4968+
4969+
if (!type_id) {
4970+
return false;
4971+
}
4972+
4973+
if (auto parent = n.get_parent()) {
4974+
return parent->name() && *type_id == *parent->name();
4975+
}
4976+
4977+
return false;
4978+
}
4979+
49614980
//-----------------------------------------------------------------------
49624981
//
49634982
auto emit(
@@ -5072,8 +5091,19 @@ class cppfront
50725091
auto& a = std::get<declaration_node::an_alias>(n.type);
50735092
assert(a);
50745093

5094+
// Helper for aliases that emit as a defining declaration.
5095+
auto const type_scope_object_alias_emits_in_phase_1_only = [&]() {
5096+
assert(
5097+
n.parent_is_type()
5098+
&& n.is_object_alias()
5099+
);
5100+
return !a->type_id
5101+
|| a->type_id->is_wildcard()
5102+
|| !has_potentially_incomplete_type(n, *a->type_id);
5103+
};
5104+
50755105
// Namespace-scope aliases are emitted in phase 1,
5076-
// type-scope object aliases in both phases 1 and 2, and
5106+
// type-scope object aliases is emitted in phase 1 and maybe 2, and
50775107
// function-scope aliases in phase 2
50785108
if (
50795109
(
@@ -5085,6 +5115,7 @@ class cppfront
50855115
n.parent_is_type()
50865116
&& n.is_object_alias()
50875117
&& printer.get_phase() == printer.phase2_func_defs
5118+
&& !type_scope_object_alias_emits_in_phase_1_only()
50885119
)
50895120
||
50905121
(
@@ -5150,21 +5181,34 @@ class cppfront
51505181
// Handle object aliases:
51515182
// - at function scope, it's const&
51525183
// - at namespace scope, it's inline constexpr
5153-
// - at type scope, it's also inline constexpr but see note (*) below
5184+
// - at type scope, it's also static constexpr but see note (*) below
51545185
else if (a->is_object_alias())
51555186
{
51565187
auto type = std::string{"auto"};
51575188
if (a->type_id) {
51585189
type = print_to_string(*a->type_id);
51595190
}
51605191

5161-
// (*) If this is at type scope, Cpp1 requires an out-of-line declaration dance
5162-
// for some cases to work - see https://stackoverflow.com/questions/11928089/
51635192
if (n.parent_is_type())
51645193
{
51655194
assert (n.parent_declaration->name());
51665195

5167-
if (printer.get_phase() == printer.phase1_type_defs_func_decls) {
5196+
if (type_scope_object_alias_emits_in_phase_1_only()) {
5197+
if (printer.get_phase() == printer.phase1_type_defs_func_decls) {
5198+
printer.print_cpp2(
5199+
"static constexpr "
5200+
+ type + " "
5201+
+ print_to_string(*n.identifier)
5202+
+ " = "
5203+
+ print_to_string( *std::get<alias_node::an_object>(a->initializer) )
5204+
+ ";\n",
5205+
n.position()
5206+
);
5207+
}
5208+
}
5209+
// At type scope, Cpp1 requires an out-of-line declaration dance
5210+
// for some cases to work - see https://stackoverflow.com/questions/11928089/
5211+
else if (printer.get_phase() == printer.phase1_type_defs_func_decls) {
51685212
printer.print_cpp2(
51695213
"static const "
51705214
+ type + " "

0 commit comments

Comments
 (0)