Skip to content

Commit

Permalink
feat: allow template specialization
Browse files Browse the repository at this point in the history
  • Loading branch information
JohelEGP committed Sep 14, 2023
1 parent ecd3726 commit eb04fb1
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 8 deletions.
18 changes: 18 additions & 0 deletions regression-tests/pure2-template-specialization.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
t: @struct <T: type> type = {
a: i32 = 1;
}
t: @struct <T: type> specialize<T> type requires std::is_void_v<T> = {
b: i32 = 2;
}
t: @struct specialize<i64> type = {
c: i32 = 3;
}
v: <T> const i32 = 1;
v: <> specialize<void> const i32 = 2;
main: () = {
[[assert Testing: t<i32>().a == 1]]
[[assert Testing: t<void>().b == 2]]
[[assert Testing: t<i64>().c == 3]]
[[assert Testing: (v<i32>) == 1]]
[[assert Testing: (v<void>) == 2]]
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
clang version 18.0.0 (https://git.uplinklabs.net/mirrors/llvm-project.git c0abd3814564a568dfc607c216e6407eaa314f46)
clang version 18.0.0 (https://github.com/llvm/llvm-project.git 3723ede3cf5324827f8fbbe7f484c2ee4d7a7204)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /home/johel/root/clang-main/bin
Empty file.
Empty file.
Empty file.
Empty file.
41 changes: 41 additions & 0 deletions regression-tests/test-results/pure2-template-specialization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

#define CPP2_USE_MODULES Yes

//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"

template<typename T> class t;


//=== Cpp2 type definitions and function declarations ===========================

template<typename T> class t {
public: cpp2::i32 a {1};
};
template<typename T> requires( std::is_void_v<T> )
class t<T> {public: cpp2::i32 b {2};
};
template<> class t<cpp2::i64> {
public: cpp2::i32 c {3};
};
template<typename T> extern cpp2::i32 const v;

auto main() -> int;


//=== Cpp2 function definitions =================================================


#line 10 "pure2-template-specialization.cpp2"
template<typename T> cpp2::i32 const v {1};
template<> cpp2::i32 const v<void> {2};
auto main() -> int{
cpp2::Testing.expects(t<cpp2::i32>().a == 1, "");
cpp2::Testing.expects(t<void>().b == 2, "");
cpp2::Testing.expects(t<cpp2::i64>().c == 3, "");
cpp2::Testing.expects((v<cpp2::i32>) == 1, "");
cpp2::Testing.expects((v<void>) == 2, "");
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pure2-template-specialization.cpp2... ok (all Cpp2, passes safety checks)

34 changes: 30 additions & 4 deletions source/cppfront.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1619,7 +1619,8 @@ class cppfront
unqualified_id_node const& n,
bool in_synthesized_multi_return = false,
bool is_local_name = true,
bool is_qualified = false
bool is_qualified = false,
bool emit_identifier = true
)
-> void
{
Expand Down Expand Up @@ -1669,7 +1670,9 @@ class cppfront
}

assert(n.identifier);
emit(*n.identifier, is_qualified); // inform the identifier if we know this is qualified
if (emit_identifier) {
emit(*n.identifier, is_qualified); // inform the identifier if we know this is qualified
}

if (n.open_angle != source_position{}) {
printer.print_cpp2("<", n.open_angle);
Expand Down Expand Up @@ -4893,6 +4896,18 @@ class cppfront
return;
}

// Do not forward declare specializations.
if (
n.is_specialization()
&& (
(n.is_type() && printer.get_phase() == printer.phase0_type_decls)
|| (n.is_object() && printer.get_phase() == printer.phase1_type_defs_func_decls)
)
)
{
return;
}

// If this is a generated declaration (negative source line number),
// add a line break before
if (
Expand Down Expand Up @@ -5160,7 +5175,7 @@ class cppfront

// Now, emit our own template parameters
if (
n.template_parameters
(n.template_parameters || n.is_specialization())
&& (
printer.get_phase() < printer.phase2_func_defs
|| n.is_object()
Expand All @@ -5178,7 +5193,12 @@ class cppfront
)
{
printer.print_cpp2("template", n.position());
emit(*n.template_parameters, false, true);
if (n.template_parameters) {
emit(*n.template_parameters, false, true);
} else {
assert(n.is_specialization());
printer.print_cpp2("<>", n.position());
}
printer.print_cpp2(" ", n.position());
}

Expand All @@ -5201,6 +5221,9 @@ class cppfront

printer.print_cpp2("class ", n.position());
emit(*n.identifier);
if (n.specialization_template_arguments) {
emit(*n.specialization_template_arguments, false, true, false, false);
}

// Type declaration
if (printer.get_phase() == printer.phase0_type_decls) {
Expand Down Expand Up @@ -5930,6 +5953,9 @@ class cppfront
}
else {
emit(*n.identifier);
if (n.specialization_template_arguments) {
emit(*n.specialization_template_arguments, false, true, false, false);
}
}

if (
Expand Down
28 changes: 25 additions & 3 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -2363,6 +2363,7 @@ struct declaration_node

std::vector<std::unique_ptr<id_expression_node>> meta_functions;
std::unique_ptr<parameter_declaration_list_node> template_parameters;
std::unique_ptr<unqualified_id_node> specialization_template_arguments;
source_position requires_pos = {};
std::unique_ptr<logical_or_expression_node> requires_clause_expression;

Expand Down Expand Up @@ -2603,6 +2604,8 @@ struct declaration_node

auto is_function_expression () const -> bool
{ return is_function() && !identifier; }
auto is_specialization() const -> bool
{ return specialization_template_arguments != nullptr; }

auto is_polymorphic() const // has base types or virtual functions
-> bool
Expand Down Expand Up @@ -4991,6 +4994,7 @@ class parser
//G
//G template-argument-list:
//G template-argument-list ',' template-argument
//G template-argument
//G
//G template-argument:
//G # note: < > << >> are not allowed in expressions until new ( is opened
Expand Down Expand Up @@ -6470,9 +6474,9 @@ class parser

//G unnamed-declaration:
//G ':' meta-functions-list? template-parameter-declaration-list? function-type requires-clause? '=' statement
//G ':' meta-functions-list? template-parameter-declaration-list? type-id? requires-clause? '=' statement
//G ':' meta-functions-list? template-parameter-declaration-list? template-specialization-argument-list? type-id? requires-clause? '=' statement
//G ':' meta-functions-list? template-parameter-declaration-list? type-id
//G ':' meta-functions-list? template-parameter-declaration-list? 'final'? 'type' requires-clause? '=' statement
//G ':' meta-functions-list? template-parameter-declaration-list? template-specialization-argument-list? 'final'? 'type' requires-clause? '=' statement
//G ':' 'namespace' '=' statement
//G
//G meta-functions-list:
Expand All @@ -6483,7 +6487,10 @@ class parser
//G 'requires' logical-or-expression
//G
//G template-parameter-declaration-list
//G '<' parameter-declaration-seq '>'
//G '<' parameter-declaration-seq? '>'
//G
//G template-specialization-argument-list:
//G 'specialize' '<' template-argument-list '>'
//G
auto unnamed_declaration(
source_position start,
Expand Down Expand Up @@ -6624,6 +6631,21 @@ class parser
n->template_parameters = std::move(template_parameters);
}

// Next is an optional template specialization argument list
if (
curr() == "specialize"
&& peek(1)
&& peek(1)->type() == lexeme::Less
)
{
auto specialization_template_arguments = unqualified_id();
if (!specialization_template_arguments) {
error("invalid template specialization argument list");
return {};
}
n->specialization_template_arguments = std::move(specialization_template_arguments);
}

auto guard =
captures_allowed
? std::make_unique<capture_groups_stack_guard>(this, &n->captures)
Expand Down

0 comments on commit eb04fb1

Please sign in to comment.