-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: accept function type argument #923
base: main
Are you sure you want to change the base?
Changes from 9 commits
d43bf58
71c7d2b
5c09723
eb9b858
64b6d02
a32271d
c92c330
79a4723
f199674
12f6501
64c84a4
8046463
1a260f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#include <cstddef> | ||
main: () = { | ||
_ = alignof(int); | ||
_ = sizeof(int); | ||
_ = typeid(int); | ||
_ = offsetof(t, a); | ||
_ = :<T> (_: T) _ = sizeof(T::value);(std::true_type()); | ||
_ = :<T> (_: T) _ = sizeof(type T::value_type);(std::true_type()); | ||
_ = alignof(const int); | ||
_ = sizeof(const int); | ||
_ = typeid(const int); | ||
_ = alignof(*int); | ||
_ = sizeof(*int); | ||
_ = typeid(*int); | ||
} | ||
t: @struct type = { | ||
a: int; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ testing_enabled: bool = false; | |
|
||
outer: @print type = { | ||
|
||
object_alias: <T> T requires true == 42; | ||
object_alias: <T> T requires true == sizeof(type T::value_type); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this just to exercise There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The former. |
||
|
||
mytype: final type = | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
|
||
|
||
//=== Cpp2 type declarations ==================================================== | ||
|
||
|
||
#include "cpp2util.h" | ||
|
||
#line 1 "mixed-function-type-argument.cpp2" | ||
|
||
#line 16 "mixed-function-type-argument.cpp2" | ||
class t; | ||
|
||
|
||
//=== Cpp2 type definitions and function declarations =========================== | ||
|
||
#line 1 "mixed-function-type-argument.cpp2" | ||
#include <cstddef> | ||
auto main() -> int; | ||
|
||
#line 16 "mixed-function-type-argument.cpp2" | ||
class t { | ||
public: int a; | ||
}; | ||
|
||
|
||
//=== Cpp2 function definitions ================================================= | ||
|
||
#line 1 "mixed-function-type-argument.cpp2" | ||
|
||
#line 2 "mixed-function-type-argument.cpp2" | ||
auto main() -> int{ | ||
static_cast<void>(alignof(int)); | ||
static_cast<void>(sizeof(int)); | ||
static_cast<void>(typeid(int)); | ||
static_cast<void>(offsetof(t, a)); | ||
static_cast<void>([]<typename T>([[maybe_unused]] T const& unnamed_param_1) mutable -> auto { return static_cast<void>(sizeof(T::value)); }(std::true_type())); | ||
static_cast<void>([]<typename T>([[maybe_unused]] T const& unnamed_param_1) mutable -> auto { return static_cast<void>(sizeof(typename T::value_type)); }(std::true_type())); | ||
static_cast<void>(alignof(int const)); | ||
static_cast<void>(sizeof(int const)); | ||
static_cast<void>(typeid(int const)); | ||
static_cast<void>(alignof(int*)); | ||
static_cast<void>(sizeof(int*)); | ||
static_cast<void>(typeid(int*)); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
mixed-function-type-argument.cpp2... ok (mixed Cpp1/Cpp2, Cpp2 code passes safety checks) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -619,13 +619,15 @@ auto to_string_view(passing_style pass) -> std::string_view { | |
} | ||
|
||
|
||
struct type_id_node; | ||
|
||
struct expression_list_node | ||
{ | ||
token const* open_paren = {}; | ||
token const* close_paren = {}; | ||
bool inside_initializer = false; | ||
|
||
struct term { | ||
struct expression_term { | ||
passing_style pass = {}; | ||
std::unique_ptr<expression_node> expr; | ||
|
||
|
@@ -637,7 +639,29 @@ struct expression_list_node | |
v.end(*this, depth); | ||
} | ||
}; | ||
std::vector< term > expressions; | ||
struct type_id_term { | ||
bool has_disambiguating_type = {}; | ||
std::unique_ptr<type_id_node> type; | ||
|
||
auto visit(auto& v, int depth) -> void; | ||
}; | ||
struct term { | ||
enum active { expression=0, type }; | ||
std::variant< | ||
std::unique_ptr<expression_term>, | ||
std::unique_ptr<type_id_term> | ||
> argument; | ||
|
||
auto visit(auto& v, int depth) | ||
-> void | ||
{ | ||
v.start(*this, depth); | ||
try_visit<expression>(argument, v, depth); | ||
try_visit<type >(argument, v, depth); | ||
v.end(*this, depth); | ||
} | ||
}; | ||
std::vector< term > arguments; | ||
|
||
|
||
// API | ||
|
@@ -648,8 +672,10 @@ struct expression_list_node | |
// This is a fold-expression if any subexpression | ||
// has an identifier named "..." | ||
auto ret = false; | ||
for (auto& x : expressions) { | ||
ret |= x.expr->is_fold_expression(); | ||
for (auto& x : arguments) { | ||
if (auto expr = std::get_if<term::expression>(&x.argument)) { | ||
ret |= (*expr)->expr->is_fold_expression(); | ||
} | ||
} | ||
return ret; | ||
} | ||
|
@@ -669,7 +695,7 @@ struct expression_list_node | |
-> void | ||
{ | ||
v.start(*this, depth); | ||
for (auto& x : expressions) { | ||
for (auto& x : arguments) { | ||
x.visit(v, depth+1); | ||
} | ||
v.end(*this, depth); | ||
|
@@ -998,7 +1024,6 @@ auto prefix_expression_node::visit(auto& v, int depth) | |
} | ||
|
||
|
||
struct type_id_node; | ||
struct template_args_tag { }; | ||
|
||
struct template_argument | ||
|
@@ -1320,6 +1345,14 @@ auto template_argument::to_string() const | |
return {}; | ||
} | ||
|
||
auto expression_list_node::type_id_term::visit(auto& v, int depth) -> void | ||
{ | ||
v.start(*this, depth); | ||
assert(type); | ||
type->visit(v, depth+1); | ||
v.end(*this, depth); | ||
} | ||
|
||
|
||
struct is_as_expression_node | ||
{ | ||
|
@@ -4423,18 +4456,30 @@ auto pretty_print_visualize(expression_list_node const& n, int indent) | |
|
||
auto ret = n.open_paren->to_string(); | ||
|
||
for (auto i = 0; auto& expr : n.expressions) { | ||
assert(expr.expr); | ||
if ( | ||
expr.pass == passing_style::out | ||
|| expr.pass == passing_style::move | ||
|| expr.pass == passing_style::forward | ||
) | ||
for (auto i = 0; auto& arg : n.arguments) { | ||
if (auto expr = std::get_if<expression_list_node::term::expression>(&arg.argument)) | ||
{ | ||
ret += to_string_view(expr.pass) + std::string{" "}; | ||
assert((*expr)->expr); | ||
if ( | ||
(*expr)->pass == passing_style::out | ||
|| (*expr)->pass == passing_style::move | ||
|| (*expr)->pass == passing_style::forward | ||
) | ||
{ | ||
ret += to_string_view((*expr)->pass) + std::string{" "}; | ||
} | ||
ret += pretty_print_visualize(*(*expr)->expr, indent); | ||
} | ||
ret += pretty_print_visualize(*expr.expr, indent); | ||
if (++i < std::ssize(n.expressions)) { | ||
else if (auto type = std::get_if<expression_list_node::term::type>(&arg.argument)) | ||
{ | ||
assert((*type)->type); | ||
if ((*type)->has_disambiguating_type) | ||
{ | ||
ret += "type "; | ||
} | ||
ret += pretty_print_visualize(*(*type)->type, indent); | ||
} | ||
if (++i < std::ssize(n.arguments)) { | ||
ret += ", "; | ||
} | ||
} | ||
|
@@ -4962,7 +5007,7 @@ auto pretty_print_visualize(declaration_node const& n, int indent, bool include_ | |
|
||
auto metafunctions = std::string{}; | ||
{ | ||
auto as_comment = | ||
auto as_comment = | ||
!n.metafunctions.empty() | ||
&& !include_metafunctions_list; | ||
if (as_comment) { | ||
|
@@ -5800,9 +5845,6 @@ class parser | |
//G postfix-expression | ||
//G prefix-operator prefix-expression | ||
//GTODO await-expression | ||
//GTODO 'sizeof' '(' type-id ')' | ||
//GTODO 'sizeof' '...' ( identifier ')' | ||
//GTODO 'alignof' '(' type-id ')' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, these should go anyway as they already work without a special grammar. And throws-expression too, since |
||
//GTODO throws-expression | ||
//G | ||
auto prefix_expression() | ||
|
@@ -5825,8 +5867,6 @@ class parser | |
error("prefix '++var' is not valid Cpp2; use postfix 'var++' instead", false); | ||
break; case lexeme::MinusMinus: | ||
error("prefix '--var' is not valid Cpp2; use postfix 'var--' instead", false); | ||
break; case lexeme::Multiply: | ||
error("prefix '*ptr' dereference is not valid Cpp2; use postfix 'ptr*' instead", false); | ||
JohelEGP marked this conversation as resolved.
Show resolved
Hide resolved
|
||
break; case lexeme::Ampersand: | ||
error("prefix '&var' address-of is not valid Cpp2; use postfix 'var&' instead", false); | ||
break; case lexeme::Tilde: | ||
|
@@ -6207,7 +6247,10 @@ class parser | |
} | ||
|
||
//G expression-list: | ||
//G 'type' type-id | ||
//G 'const' type-id | ||
//G parameter-direction? expression | ||
//G type-id | ||
//G expression-list ',' parameter-direction? expression | ||
//G | ||
auto expression_list( | ||
|
@@ -6216,11 +6259,39 @@ class parser | |
) | ||
-> std::unique_ptr<expression_list_node> | ||
{ | ||
auto pass = passing_style::in; | ||
auto pass = std::optional<passing_style>(); | ||
auto n = std::make_unique<expression_list_node>(); | ||
n->open_paren = open_paren; | ||
n->inside_initializer = inside_initializer; | ||
|
||
auto add_expr = [&](std::unique_ptr<expression_node>&& x) { | ||
n->arguments.push_back( | ||
{std::make_unique<expression_list_node::expression_term>( | ||
expression_list_node::expression_term{ | ||
pass.value_or(passing_style::in), | ||
std::move(x) | ||
} | ||
)} | ||
); | ||
pass.reset(); | ||
}; | ||
auto parses_type_id = [&]() -> bool { | ||
if (pass.has_value()) { | ||
return false; | ||
} | ||
auto res = std::make_unique<expression_list_node::type_id_term>(); | ||
next((res->has_disambiguating_type = curr() == "type")); | ||
if ((res->type = type_id())) | ||
{ | ||
n->arguments.push_back( {std::move(res)} ); | ||
return true; | ||
} | ||
if (curr().type() == lexeme::Multiply) { | ||
error("prefix '*ptr' dereference is not valid Cpp2; use postfix 'ptr*' instead", false); | ||
} | ||
return false; | ||
}; | ||
|
||
if (auto dir = to_passing_style(curr()); | ||
( | ||
dir == passing_style::out | ||
|
@@ -6234,15 +6305,29 @@ class parser | |
pass = dir; | ||
next(); | ||
} | ||
auto x = expression(); | ||
decltype(expression()) x = {}; | ||
// If it doesn't start with * or const (which can only be a type id), | ||
// try parsing it as an expression | ||
if ( | ||
curr().type() != lexeme::Multiply // '*' | ||
&& curr() != "const" // 'const' | ||
&& curr() != "type" // 'type' | ||
) | ||
{ | ||
x = expression(); | ||
} | ||
|
||
// If this is an empty expression_list, we're done | ||
if (!x) { | ||
return n; | ||
if (!x) | ||
{ | ||
if (!parses_type_id()) { | ||
return n; | ||
} | ||
} | ||
|
||
// Otherwise remember the first expression | ||
n->expressions.push_back( { pass, std::move(x) } ); | ||
else { | ||
add_expr( std::move(x) ); | ||
} | ||
// and see if there are more... | ||
while (curr().type() == lexeme::Comma) { | ||
next(); | ||
|
@@ -6256,12 +6341,29 @@ class parser | |
pass = dir; | ||
next(); | ||
} | ||
auto expr = expression(); | ||
if (!expr) { | ||
decltype(expression()) expr = {}; | ||
// If it doesn't start with * or const (which can only be a type id), | ||
// try parsing it as an expression | ||
if ( | ||
curr().type() != lexeme::Multiply // '*' | ||
&& curr() != "const" // 'const' | ||
&& curr() != "type" // 'type' | ||
) | ||
{ | ||
expr = expression(); | ||
} | ||
if ( | ||
!expr | ||
&& !parses_type_id() | ||
) | ||
{ | ||
error("invalid text in expression list", true, {}, true); | ||
return {}; | ||
} | ||
n->expressions.push_back( { pass, std::move(expr) } ); | ||
else | ||
{ | ||
add_expr( std::move(expr) ); | ||
} | ||
} | ||
return n; | ||
} | ||
|
@@ -8996,7 +9098,7 @@ class parse_tree_printer : printing_visitor | |
<< static_cast<void const*>(n.my_statement) << "]\n"; | ||
} | ||
|
||
auto start(expression_list_node::term const&n, int indent) -> void | ||
auto start(expression_list_node::expression_term const&n, int indent) -> void | ||
JohelEGP marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
o << pre(indent) << "expression-list term\n"; | ||
if (n.pass == passing_style::out) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there intended to be a difference between lines 7 and 8? Or is the
type
intended to be optional?If there's no difference, can you show a case where it's required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second one needs the disambiguating
type
.See https://cpp1.godbolt.org/z/PY53n6Kvf (generated from https://cpp2.godbolt.org/z/KK15vf6Y5):
error: dependent-name 'T::value_type' is parsed as a non-type, but instantiation yields a type
.error: missing 'typename' prior to dependent type name 'integral_constant<bool, true>::value_type'
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
D'oh, now I see it. I missed the
_type
suffix that changed the meaning, sorry.