Skip to content

Commit b7b09e6

Browse files
committed
feat: allow template specialization
1 parent 083c8a0 commit b7b09e6

7 files changed

+121
-7
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
t: @struct <T> type = {
2+
a: i32 = 1;
3+
}
4+
t: @struct <T> specialize<T> type requires std::is_void_v<T> = {
5+
b: i32 = 2;
6+
}
7+
t: @struct specialize<i64> type = {
8+
c: i32 = 3;
9+
}
10+
v: <T> const i32 = 1;
11+
v: <> specialize<void> const i32 = 2;
12+
v: specialize<i64> const i32 = 3;
13+
main: () = {
14+
[[assert Testing: t<i32>().a == 1]]
15+
[[assert Testing: t<void>().b == 2]]
16+
[[assert Testing: t<i64>().c == 3]]
17+
[[assert Testing: v<i32> == 1]]
18+
[[assert Testing: v<void> == 2]]
19+
[[assert Testing: v<i64> == 3]]
20+
}

regression-tests/test-results/gcc-13/pure2-template-specialization.cpp.execution

Whitespace-only changes.

regression-tests/test-results/gcc-13/pure2-template-specialization.cpp.output

Whitespace-only changes.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
template<typename T> class t;
10+
11+
12+
//=== Cpp2 type definitions and function declarations ===========================
13+
14+
template<typename T> class t {
15+
public: cpp2::i32 a {1};
16+
};
17+
template<typename T> requires( std::is_void_v<T> )
18+
class t<T> {public: cpp2::i32 b {2};
19+
};
20+
template<> class t<cpp2::i64> {
21+
public: cpp2::i32 c {3};
22+
};
23+
template<typename T> extern cpp2::i32 const v;
24+
25+
#line 13 "pure2-template-specialization.cpp2"
26+
auto main() -> int;
27+
28+
29+
//=== Cpp2 function definitions =================================================
30+
31+
32+
#line 10 "pure2-template-specialization.cpp2"
33+
template<typename T> cpp2::i32 const v {1};
34+
template<> cpp2::i32 const v<void> {2};
35+
template<> cpp2::i32 const v<cpp2::i64> {3};
36+
auto main() -> int{
37+
cpp2::Testing.expects(t<cpp2::i32>().a == 1, "");
38+
cpp2::Testing.expects(t<void>().b == 2, "");
39+
cpp2::Testing.expects(t<cpp2::i64>().c == 3, "");
40+
cpp2::Testing.expects(v<cpp2::i32> == 1, "");
41+
cpp2::Testing.expects(v<void> == 2, "");
42+
cpp2::Testing.expects(v<cpp2::i64> == 3, "");
43+
}
44+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-template-specialization.cpp2... ok (all Cpp2, passes safety checks)
2+

source/cppfront.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,8 @@ class cppfront
16481648
unqualified_id_node const& n,
16491649
bool in_synthesized_multi_return = false,
16501650
bool is_local_name = true,
1651-
bool is_qualified = false
1651+
bool is_qualified = false,
1652+
bool emit_identifier = true
16521653
)
16531654
-> void
16541655
{
@@ -1698,7 +1699,9 @@ class cppfront
16981699
}
16991700

17001701
assert(n.identifier);
1701-
emit(*n.identifier, is_qualified); // inform the identifier if we know this is qualified
1702+
if (emit_identifier) {
1703+
emit(*n.identifier, is_qualified); // inform the identifier if we know this is qualified
1704+
}
17021705

17031706
if (n.open_angle != source_position{}) {
17041707
printer.print_cpp2("<", n.open_angle);
@@ -5055,6 +5058,18 @@ class cppfront
50555058
return;
50565059
}
50575060

5061+
// Do not forward declare specializations.
5062+
if (
5063+
n.is_specialization()
5064+
&& (
5065+
(n.is_type() && printer.get_phase() == printer.phase0_type_decls)
5066+
|| (n.is_object() && printer.get_phase() == printer.phase1_type_defs_func_decls)
5067+
)
5068+
)
5069+
{
5070+
return;
5071+
}
5072+
50585073
// If this is a generated declaration (negative source line number),
50595074
// add a line break before
50605075
if (
@@ -5361,7 +5376,7 @@ class cppfront
53615376

53625377
// Now, emit our own template parameters
53635378
if (
5364-
n.template_parameters
5379+
(n.template_parameters || n.is_specialization())
53655380
&& (
53665381
printer.get_phase() < printer.phase2_func_defs
53675382
|| n.is_object()
@@ -5379,7 +5394,12 @@ class cppfront
53795394
)
53805395
{
53815396
printer.print_cpp2("template", n.position());
5382-
emit(*n.template_parameters, false, true);
5397+
if (n.template_parameters) {
5398+
emit(*n.template_parameters, false, true);
5399+
} else {
5400+
assert(n.is_specialization());
5401+
printer.print_cpp2("<>", n.position());
5402+
}
53835403
printer.print_cpp2(" ", n.position());
53845404
}
53855405

@@ -5402,6 +5422,9 @@ class cppfront
54025422

54035423
printer.print_cpp2("class ", n.position());
54045424
emit(*n.identifier);
5425+
if (n.specialization_template_arguments) {
5426+
emit(*n.specialization_template_arguments, false, true, false, false);
5427+
}
54055428

54065429
// Type declaration
54075430
if (printer.get_phase() == printer.phase0_type_decls) {
@@ -6144,6 +6167,9 @@ class cppfront
61446167
}
61456168
else {
61466169
emit(*n.identifier);
6170+
if (n.specialization_template_arguments) {
6171+
emit(*n.specialization_template_arguments, false, true, false, false);
6172+
}
61476173
}
61486174

61496175
if (

source/parse.h

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,6 +2538,7 @@ struct declaration_node
25382538

25392539
std::vector<std::unique_ptr<id_expression_node>> metafunctions;
25402540
std::unique_ptr<parameter_declaration_list_node> template_parameters;
2541+
std::unique_ptr<unqualified_id_node> specialization_template_arguments;
25412542
source_position requires_pos = {};
25422543
std::unique_ptr<logical_or_expression_node> requires_clause_expression;
25432544

@@ -2822,6 +2823,8 @@ struct declaration_node
28222823

28232824
auto is_function_expression () const -> bool
28242825
{ return is_function() && !identifier; }
2826+
auto is_specialization() const -> bool
2827+
{ return specialization_template_arguments != nullptr; }
28252828

28262829
auto is_polymorphic() const // has base types or virtual functions
28272830
-> bool
@@ -6160,6 +6163,7 @@ class parser
61606163
//G
61616164
//G template-argument-list:
61626165
//G template-argument-list ',' template-argument
6166+
//G template-argument
61636167
//G
61646168
//G template-argument:
61656169
//G # note: < > << >> are not allowed in expressions until new ( is opened
@@ -7718,9 +7722,9 @@ class parser
77187722
//G unnamed-declaration:
77197723
//G ':' meta-functions-list? template-parameter-declaration-list? function-type requires-clause? '=' statement
77207724
//G ':' meta-functions-list? template-parameter-declaration-list? function-type statement
7721-
//G ':' meta-functions-list? template-parameter-declaration-list? type-id? requires-clause? '=' statement
7725+
//G ':' meta-functions-list? template-parameter-declaration-list? template-specialization-argument-list? type-id? requires-clause? '=' statement
77227726
//G ':' meta-functions-list? template-parameter-declaration-list? type-id
7723-
//G ':' meta-functions-list? template-parameter-declaration-list? 'final'? 'type' requires-clause? '=' statement
7727+
//G ':' meta-functions-list? template-parameter-declaration-list? template-specialization-argument-list? 'final'? 'type' requires-clause? '=' statement
77247728
//G ':' 'namespace' '=' statement
77257729
//G
77267730
//G meta-functions-list:
@@ -7732,7 +7736,10 @@ class parser
77327736
//G 'requires' logical-or-expression
77337737
//G
77347738
//G template-parameter-declaration-list
7735-
//G '<' parameter-declaration-seq '>'
7739+
//G '<' parameter-declaration-seq? '>'
7740+
//G
7741+
//G template-specialization-argument-list:
7742+
//G 'specialize' '<' template-argument-list '>'
77367743
//G
77377744
auto unnamed_declaration(
77387745
source_position start,
@@ -7877,6 +7884,21 @@ class parser
78777884
n->template_parameters = std::move(template_parameters);
78787885
}
78797886

7887+
// Next is an optional template specialization argument list
7888+
if (
7889+
curr() == "specialize"
7890+
&& peek(1)
7891+
&& peek(1)->type() == lexeme::Less
7892+
)
7893+
{
7894+
auto specialization_template_arguments = unqualified_id();
7895+
if (!specialization_template_arguments) {
7896+
error("invalid template specialization argument list");
7897+
return {};
7898+
}
7899+
n->specialization_template_arguments = std::move(specialization_template_arguments);
7900+
}
7901+
78807902
auto guard =
78817903
captures_allowed
78827904
? std::make_unique<capture_groups_stack_guard>(this, &n->captures)

0 commit comments

Comments
 (0)