Skip to content

Commit 7dd5d76

Browse files
committed
feat: allow object alias specialization
1 parent 7e96f5d commit 7dd5d76

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

regression-tests/pure2-template-specialization.cpp2

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@ t: @struct specialize<i64> type = {
1010
v: <T> const i32 = 1;
1111
v: <> specialize<void> const i32 = 2;
1212
v: specialize<i64> const i32 = 3;
13+
v: specialize<i16> std::optional<i32> == 4;
14+
v: <> specialize<i8> std::optional<i8> == 5;
15+
v: <T> specialize<* T> std::optional<int> == 6;
1316
main: () = {
1417
[[assert Testing: t<i32>().a == 1]]
1518
[[assert Testing: t<void>().b == 2]]
1619
[[assert Testing: t<i64>().c == 3]]
1720
[[assert Testing: v<i32> == 1]]
1821
[[assert Testing: v<void> == 2]]
1922
[[assert Testing: v<i64> == 3]]
23+
static_assert(v<i16> == 4);
24+
static_assert(v<i8> == 5);
25+
static_assert(v<* int> == 6);
2026
}

regression-tests/test-results/pure2-template-specialization.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ template<> class t<cpp2::i64> {
2323
template<typename T> extern cpp2::i32 const v;
2424

2525
#line 13 "pure2-template-specialization.cpp2"
26+
template<> std::optional<cpp2::i32> inline constexpr v<cpp2::i16> = 4;
27+
template<> std::optional<cpp2::i8> inline constexpr v<cpp2::i8> = 5;
28+
template<typename T> std::optional<int> inline constexpr v<T*> = 6;
2629
auto main() -> int;
2730

2831

@@ -33,12 +36,17 @@ auto main() -> int;
3336
template<typename T> cpp2::i32 const v {1};
3437
template<> cpp2::i32 const v<void> {2};
3538
template<> cpp2::i32 const v<cpp2::i64> {3};
39+
40+
#line 16 "pure2-template-specialization.cpp2"
3641
auto main() -> int{
3742
cpp2::Testing.expects(t<cpp2::i32>().a == 1, "");
3843
cpp2::Testing.expects(t<void>().b == 2, "");
3944
cpp2::Testing.expects(t<cpp2::i64>().c == 3, "");
4045
cpp2::Testing.expects(v<cpp2::i32> == 1, "");
4146
cpp2::Testing.expects(v<void> == 2, "");
4247
cpp2::Testing.expects(v<cpp2::i64> == 3, "");
48+
static_assert(v<cpp2::i16> == 4);
49+
static_assert(v<cpp2::i8> == 5);
50+
static_assert(v<int*> == 6);
4351
}
4452

source/cppfront.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5133,6 +5133,8 @@ class cppfront
51335133
printer.print_cpp2("template", n.position());
51345134
emit(*n.template_parameters, false, true);
51355135
printer.print_cpp2(" ", n.position());
5136+
} else if (n.is_specialization()) {
5137+
printer.print_cpp2("template<> ", n.position());
51365138
}
51375139

51385140
// Emit requires clause if any
@@ -5178,6 +5180,13 @@ class cppfront
51785180
if (n.parent_is_type())
51795181
{
51805182
assert (n.parent_declaration->name());
5183+
if (n.specialization_template_arguments) {
5184+
errors.emplace_back(
5185+
n.position(),
5186+
"(temporary alpha limitation) an object alias in type scope cannot be specialized"
5187+
);
5188+
return;
5189+
}
51815190

51825191
if (printer.get_phase() == printer.phase1_type_defs_func_decls) {
51835192
printer.print_cpp2(
@@ -5223,10 +5232,16 @@ class cppfront
52235232
intro = "inline constexpr";
52245233
}
52255234

5235+
auto specialization_template_arguments = std::string{};
5236+
if (n.specialization_template_arguments) {
5237+
specialization_template_arguments = print_to_string(*n.specialization_template_arguments, false, true, false, false);
5238+
}
5239+
52265240
printer.print_cpp2(
52275241
type + " "
52285242
+ intro + " "
52295243
+ print_to_string(*n.identifier)
5244+
+ specialization_template_arguments
52305245
+ " = "
52315246
+ print_to_string( *std::get<alias_node::an_object>(a->initializer) )
52325247
+ ";\n",

source/parse.h

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4869,7 +4869,8 @@ auto pretty_print_visualize(declaration_node const& n, int indent, bool include_
48694869
object_type_id += " " + pretty_print_visualize(*a->type_id, indent);
48704870
}
48714871

4872-
ret += template_params;
4872+
ret += template_params
4873+
+ specialization_args;
48734874
if (a->is_type_alias()) {
48744875
auto& t = std::get<alias_node::a_type>(a->initializer);
48754876
ret += " type"
@@ -7898,12 +7899,12 @@ class parser
78987899
&& peek(1)->type() == lexeme::Less
78997900
)
79007901
{
7901-
auto specialization_template_arguments = unqualified_id();
7902-
if (!specialization_template_arguments) {
7903-
error("invalid template specialization argument list");
7904-
return {};
7905-
}
7906-
n->specialization_template_arguments = std::move(specialization_template_arguments);
7902+
auto specialization_template_arguments = unqualified_id();
7903+
if (!specialization_template_arguments) {
7904+
error("invalid template specialization argument list");
7905+
return {};
7906+
}
7907+
n->specialization_template_arguments = std::move(specialization_template_arguments);
79077908
}
79087909

79097910
auto guard =
@@ -8271,7 +8272,7 @@ class parser
82718272
//G alias:
82728273
//G ':' template-parameter-declaration-list? 'type' requires-clause? '==' type-id ';'
82738274
//G ':' 'namespace' '==' id-expression ';'
8274-
//G ':' template-parameter-declaration-list? type-id? requires-clause? '==' expression ';'
8275+
//G ':' template-parameter-declaration-list? template-specialization-argument-list? type-id? requires-clause? '==' expression ';'
82758276
//G
82768277
//GT ':' function-type '==' expression ';'
82778278
//GT # See commit 63efa6ed21c4d4f4f136a7a73e9f6b2c110c81d7 comment
@@ -8300,12 +8301,34 @@ class parser
83008301
n->template_parameters = std::move(template_parameters);
83018302
}
83028303

8304+
// Next is an optional template specialization argument list
8305+
if (
8306+
curr() == "specialize"
8307+
&& peek(1)
8308+
&& peek(1)->type() == lexeme::Less
8309+
)
8310+
{
8311+
auto specialization_template_arguments = unqualified_id();
8312+
if (!specialization_template_arguments) {
8313+
pos = start_pos; // backtrack
8314+
return {};
8315+
}
8316+
n->specialization_template_arguments = std::move(specialization_template_arguments);
8317+
}
8318+
83038319
auto a = std::make_unique<alias_node>( &curr() );
83048320

83058321
// Next must be 'type', 'namespace', a type-id, or we're at the 'requires' or '=='
83068322
if (curr() == "type")
83078323
{
83088324
next();
8325+
if (n->specialization_template_arguments) {
8326+
errors.emplace_back(
8327+
curr().position(),
8328+
"a type alias cannot be specialized"
8329+
);
8330+
return {};
8331+
}
83098332
}
83108333
else if (curr() == "namespace")
83118334
{
@@ -8317,6 +8340,13 @@ class parser
83178340
);
83188341
return {};
83198342
}
8343+
if (n->specialization_template_arguments) {
8344+
errors.emplace_back(
8345+
curr().position(),
8346+
"a namespace alias cannot be specialized"
8347+
);
8348+
return {};
8349+
}
83208350
}
83218351
else if (curr().type() != lexeme::EqualComparison && curr() != "requires")
83228352
{

0 commit comments

Comments
 (0)