gccrs: Fix multiple issues with variadic representation

The new variadic representation has introduced multiple issues and ICE
into the codebase. Some early passes in the compiler depend on the
parameters all having a type and being an actual parameter.

gcc/rust/ChangeLog:

	* ast/rust-ast.cc (ExternalFunctionItem::as_string): Adapt as_string
	function to the new ast representation.
	(NamedFunctionParam::as_string): Likewise.
	* ast/rust-item.h: Add a function to test whether a FunctionParam has
	a name pattern.
	* expand/rust-cfg-strip.cc (CfgStrip::visit): Adapt cfg strip visitor
	for the new variadic arguments.
	* hir/rust-ast-lower-extern.h: Adapt lowering to the new variadic
	function representation.
	* metadata/rust-export-metadata.cc (ExportContext::emit_function):
	Change call to constructor.
	* parse/rust-parse-impl.h (Parser::parse_named_function_param): Change
	NamedFunctionParam parsing to accomodate new variadic representation.
	(Parser::parse_external_item): Change external item parsing to use the
	new NamedFunctionParam variadics.
	* parse/rust-parse.h: Add new parsing function prototypes.
	* ast/rust-ast-collector.cc (TokenCollector::visit): Rework token
	collection to take into account variadic parameters.
	* ast/rust-ast-visitor.cc: Likewise.
	* expand/rust-expand-visitor.cc (ExpandVisitor::visit): Change function
	bound to avoid getting the type of a variadic parameter.
	* resolve/rust-ast-resolve-item.cc (ResolveExternItem::visit):
	Likewise.
	* resolve/rust-early-name-resolver.cc (EarlyNameResolver::visit):
	Likewise.

Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
This commit is contained in:
Pierre-Emmanuel Patry 2023-10-19 15:23:26 +02:00 committed by Arthur Cohen
parent df4e37c7dc
commit 2272cfb53e
12 changed files with 243 additions and 230 deletions

View file

@ -172,9 +172,22 @@ TokenCollector::visit (Visitable &v)
void
TokenCollector::visit (FunctionParam &param)
{
visit (param.get_pattern ());
push (Rust::Token::make (COLON, UNDEF_LOCATION));
visit (param.get_type ());
visit_items_as_lines (param.get_outer_attrs ());
if (!param.is_variadic ())
{
visit (param.get_pattern ());
push (Rust::Token::make (COLON, UNDEF_LOCATION));
visit (param.get_type ());
}
else
{
if (param.has_name ())
{
visit (param.get_pattern ());
push (Rust::Token::make (COLON, UNDEF_LOCATION));
}
push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
}
}
void
@ -293,9 +306,23 @@ void
TokenCollector::visit (NamedFunctionParam &param)
{
auto name = param.get_name ();
push (Rust::Token::make_identifier (param.get_locus (), std::move (name)));
push (Rust::Token::make (COLON, UNDEF_LOCATION));
visit (param.get_type ());
if (!param.is_variadic ())
{
push (
Rust::Token::make_identifier (param.get_locus (), std::move (name)));
push (Rust::Token::make (COLON, UNDEF_LOCATION));
visit (param.get_type ());
}
else
{
if (name != "")
{
push (Rust::Token::make_identifier (param.get_locus (),
std::move (name)));
push (Rust::Token::make (COLON, UNDEF_LOCATION));
}
push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
}
}
void
@ -2209,13 +2236,6 @@ TokenCollector::visit (ExternalFunctionItem &function)
push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
visit_items_joined_by_separator (function.get_function_params ());
if (function.is_variadic ())
{
push (Rust::Token::make (COMMA, UNDEF_LOCATION));
// TODO: Add variadic outer attributes?
// TODO: Add variadic name once implemented.
push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
}
push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
if (function.has_return_type ())

View file

@ -721,8 +721,11 @@ void
DefaultASTVisitor::visit (AST::FunctionParam &param)
{
visit_outer_attrs (param);
visit (param.get_pattern ());
visit (param.get_type ());
if (param.has_name ())
visit (param.get_pattern ());
if (!param.is_variadic ())
visit (param.get_type ());
}
void
@ -1054,7 +1057,8 @@ void
DefaultASTVisitor::visit (AST::NamedFunctionParam &param)
{
visit_outer_attrs (param);
visit (param.get_type ());
if (!param.is_variadic ())
visit (param.get_type ());
}
void

View file

@ -3036,7 +3036,7 @@ ExternalFunctionItem::as_string () const
// function params
str += "\n Function params: ";
if (function_params.empty () && !has_variadics)
if (function_params.empty ())
{
str += "none";
}
@ -3044,21 +3044,6 @@ ExternalFunctionItem::as_string () const
{
for (const auto &param : function_params)
str += "\n " + param.as_string ();
if (has_variadics)
{
str += "\n variadic outer attrs: ";
if (has_variadic_outer_attrs ())
{
for (const auto &attr : variadic_outer_attrs)
str += "\n " + attr.as_string ();
}
else
{
str += "none";
}
str += "\n ... (variadic)";
}
}
// add type on new line
@ -3080,9 +3065,13 @@ NamedFunctionParam::as_string () const
{
std::string str = append_attributes (outer_attrs, OUTER);
str += "\n" + name;
if (has_name ())
str += "\n" + name;
str += "\n Type: " + param_type->as_string ();
if (is_variadic ())
str += "...";
else
str += "\n Type: " + param_type->as_string ();
return str;
}

View file

@ -618,6 +618,8 @@ public:
return param_name;
}
bool has_name () const { return param_name != nullptr; }
// TODO: is this better? Or is a "vis_block" better?
std::unique_ptr<Type> &get_type ()
{
@ -4171,7 +4173,7 @@ class NamedFunctionParam
public:
/* Returns whether the named function parameter has a name (i.e. name is not
* '_'). */
bool has_name () const { return name != "_"; }
bool has_name () const { return name != "_" && name != ""; }
bool has_outer_attrs () const { return !outer_attrs.empty (); }
@ -4182,6 +4184,8 @@ public:
return param_type == nullptr && !variadic;
}
bool is_variadic () const { return variadic; }
std::string get_name () const { return name; }
location_t get_locus () { return locus; }
@ -4294,8 +4298,6 @@ class ExternalFunctionItem : public ExternalItem
WhereClause where_clause;
std::vector<NamedFunctionParam> function_params;
bool has_variadics;
std::vector<Attribute> variadic_outer_attrs;
public:
// Returns whether item has generic parameters.
@ -4314,12 +4316,10 @@ public:
bool has_visibility () const { return !visibility.is_error (); }
// Returns whether item has variadic parameters.
bool is_variadic () const { return has_variadics; }
// Returns whether item has outer attributes on its variadic parameters.
bool has_variadic_outer_attrs () const
bool is_variadic () const
{
return !variadic_outer_attrs.empty ();
return function_params.size () != 0
&& function_params.back ().is_variadic ();
}
location_t get_locus () const { return locus; }
@ -4331,17 +4331,14 @@ public:
Identifier item_name,
std::vector<std::unique_ptr<GenericParam>> generic_params,
std::unique_ptr<Type> return_type, WhereClause where_clause,
std::vector<NamedFunctionParam> function_params, bool has_variadics,
std::vector<Attribute> variadic_outer_attrs, Visibility vis,
std::vector<NamedFunctionParam> function_params, Visibility vis,
std::vector<Attribute> outer_attrs, location_t locus)
: ExternalItem (), outer_attrs (std::move (outer_attrs)),
visibility (std::move (vis)), item_name (std::move (item_name)),
locus (locus), generic_params (std::move (generic_params)),
return_type (std::move (return_type)),
where_clause (std::move (where_clause)),
function_params (std::move (function_params)),
has_variadics (has_variadics),
variadic_outer_attrs (std::move (variadic_outer_attrs))
function_params (std::move (function_params))
{
// TODO: assert that if has variadic outer attrs, then has_variadics is
// true?
@ -4351,10 +4348,7 @@ public:
ExternalFunctionItem (ExternalFunctionItem const &other)
: outer_attrs (other.outer_attrs), visibility (other.visibility),
item_name (other.item_name), locus (other.locus),
where_clause (other.where_clause),
function_params (other.function_params),
has_variadics (other.has_variadics),
variadic_outer_attrs (other.variadic_outer_attrs)
where_clause (other.where_clause), function_params (other.function_params)
{
node_id = other.node_id;
// guard to prevent null pointer dereference
@ -4375,8 +4369,6 @@ public:
locus = other.locus;
where_clause = other.where_clause;
function_params = other.function_params;
has_variadics = other.has_variadics;
variadic_outer_attrs = other.variadic_outer_attrs;
node_id = other.node_id;
// guard to prevent null pointer dereference

View file

@ -2603,12 +2603,15 @@ CfgStrip::visit (AST::ExternalFunctionItem &item)
continue;
}
auto &type = param.get_type ();
type->accept_vis (*this);
if (!param.is_variadic ())
{
auto &type = param.get_type ();
param.get_type ()->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
// increment if nothing else happens
++it;

View file

@ -1265,12 +1265,9 @@ ExpandVisitor::visit (AST::ExternalFunctionItem &item)
for (auto &param : item.get_generic_params ())
visit (param);
// FIXME: Should this work? What is the difference between NamedFunctionParam
// and FunctionParam?
// expand_function_params (item.get_function_params ());
for (auto &param : item.get_function_params ())
maybe_expand_type (param.get_type ());
if (!param.is_variadic ())
maybe_expand_type (param.get_type ());
if (item.has_return_type ())
maybe_expand_type (item.get_return_type ());

View file

@ -110,7 +110,7 @@ public:
translated = new HIR::ExternalFunctionItem (
mapping, function.get_identifier (), std::move (generic_params),
std::unique_ptr<HIR::Type> (return_type), std::move (where_clause),
std::move (function_params), function.is_variadic (), std::move (vis),
std::move (function_params), is_variadic, std::move (vis),
function.get_outer_attrs (), function.get_locus ());
}

View file

@ -118,11 +118,12 @@ ExportContext::emit_function (const HIR::Function &fn)
function_params.push_back (std::move (p));
}
AST::ExternalItem *external_item = new AST::ExternalFunctionItem (
item_name, {} /* generic_params */, std::move (return_type),
where_clause, std::move (function_params), false /* has_variadics */,
{} /* variadic_outer_attrs */, vis, function.get_outer_attrs (),
function.get_locus ());
AST::ExternalItem *external_item
= new AST::ExternalFunctionItem (item_name, {} /* generic_params */,
std::move (return_type), where_clause,
std::move (function_params), vis,
function.get_outer_attrs (),
function.get_locus ());
std::vector<std::unique_ptr<AST::ExternalItem>> external_items;
external_items.push_back (

View file

@ -5963,6 +5963,161 @@ Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
std::move (outer_attrs), locus));
}
template <typename ManagedTokenSource>
AST::NamedFunctionParam
Parser<ManagedTokenSource>::parse_named_function_param ()
{
AST::AttrVec outer_attrs = parse_outer_attributes ();
location_t locus = lexer.peek_token ()->get_locus ();
if (lexer.peek_token ()->get_id () == ELLIPSIS)
{
lexer.skip_token (); // Skip ellipsis
return AST::NamedFunctionParam (std::move (outer_attrs), locus);
}
// parse identifier/_
std::string name;
const_TokenPtr t = lexer.peek_token ();
location_t name_location = t->get_locus ();
switch (t->get_id ())
{
case IDENTIFIER:
name = t->get_str ();
lexer.skip_token ();
break;
case UNDERSCORE:
name = "_";
lexer.skip_token ();
break;
default:
// this is not a function param, but not necessarily an error
return AST::NamedFunctionParam::create_error ();
}
if (!skip_token (COLON))
{
// skip after somewhere?
return AST::NamedFunctionParam::create_error ();
}
// parse (required) type
std::unique_ptr<AST::Type> param_type = parse_type ();
if (param_type == nullptr)
{
Error error (
lexer.peek_token ()->get_locus (),
"could not parse param type in extern block function declaration");
add_error (std::move (error));
skip_after_semicolon ();
return AST::NamedFunctionParam::create_error ();
}
return AST::NamedFunctionParam (std::move (name), std::move (param_type),
std::move (outer_attrs), name_location);
}
template <typename ManagedTokenSource>
template <typename EndTokenPred>
std::vector<AST::NamedFunctionParam>
Parser<ManagedTokenSource>::parse_named_function_params (
EndTokenPred is_end_token)
{
std::vector<AST::NamedFunctionParam> params;
if (is_end_token (lexer.peek_token ()->get_id ()))
return params;
auto initial_param = parse_named_function_param ();
if (initial_param.is_error ())
return params;
params.push_back (std::move (initial_param));
auto t = lexer.peek_token ();
while (t->get_id () == COMMA)
{
lexer.skip_token ();
if (is_end_token (lexer.peek_token ()->get_id ()))
break;
auto param = parse_named_function_param ();
if (param.is_error ())
{
Error error (lexer.peek_token ()->get_locus (),
"failed to parse param in c function params");
add_error (error);
return std::vector<AST::NamedFunctionParam> ();
}
params.push_back (std::move (param));
t = lexer.peek_token ();
}
params.shrink_to_fit ();
return params;
}
template <typename ManagedTokenSource>
std::unique_ptr<AST::ExternalFunctionItem>
Parser<ManagedTokenSource>::parse_external_function_item (
AST::Visibility vis, AST::AttrVec outer_attrs)
{
location_t locus = lexer.peek_token ()->get_locus ();
// parse extern function declaration item
// skip function token
lexer.skip_token ();
// parse identifier
const_TokenPtr ident_tok = expect_token (IDENTIFIER);
if (ident_tok == nullptr)
{
skip_after_semicolon ();
return nullptr;
}
Identifier ident{ident_tok};
// parse (optional) generic params
std::vector<std::unique_ptr<AST::GenericParam>> generic_params
= parse_generic_params_in_angles ();
if (!skip_token (LEFT_PAREN))
{
skip_after_semicolon ();
return nullptr;
}
// parse parameters
std::vector<AST::NamedFunctionParam> function_params
= parse_named_function_params (
[] (TokenId id) { return id == RIGHT_PAREN; });
if (!skip_token (RIGHT_PAREN))
{
skip_after_semicolon ();
return nullptr;
}
// parse (optional) return type
std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
// parse (optional) where clause
AST::WhereClause where_clause = parse_where_clause ();
if (!skip_token (SEMICOLON))
{
// skip somewhere?
return nullptr;
}
function_params.shrink_to_fit ();
return std::unique_ptr<AST::ExternalFunctionItem> (
new AST::ExternalFunctionItem (
std::move (ident), std::move (generic_params), std::move (return_type),
std::move (where_clause), std::move (function_params), std::move (vis),
std::move (outer_attrs), locus));
}
// Parses a single extern block item (static or function declaration).
template <typename ManagedTokenSource>
std::unique_ptr<AST::ExternalItem>
@ -6031,112 +6186,9 @@ Parser<ManagedTokenSource>::parse_external_item ()
has_mut, std::move (vis),
std::move (outer_attrs), locus));
}
case FN_TOK: {
// parse extern function declaration item
// skip function token
lexer.skip_token ();
// parse identifier
const_TokenPtr ident_tok = expect_token (IDENTIFIER);
if (ident_tok == nullptr)
{
skip_after_semicolon ();
return nullptr;
}
Identifier ident{ident_tok};
// parse (optional) generic params
std::vector<std::unique_ptr<AST::GenericParam>> generic_params
= parse_generic_params_in_angles ();
if (!skip_token (LEFT_PAREN))
{
skip_after_semicolon ();
return nullptr;
}
// parse parameters
std::vector<AST::NamedFunctionParam> function_params;
bool is_variadic = false;
AST::AttrVec variadic_attrs;
const_TokenPtr t = lexer.peek_token ();
while (t->get_id () != RIGHT_PAREN)
{
AST::AttrVec maybe_variadic_attrs = parse_outer_attributes ();
if (lexer.peek_token ()->get_id () == ELLIPSIS)
{
// variadic - use attrs for this
lexer.skip_token ();
is_variadic = true;
variadic_attrs = std::move (maybe_variadic_attrs);
t = lexer.peek_token ();
if (t->get_id () != RIGHT_PAREN)
{
Error error (t->get_locus (),
"expected right parentheses after variadic in "
"named function "
"parameters, found %qs",
t->get_token_description ());
add_error (std::move (error));
skip_after_semicolon ();
return nullptr;
}
break;
}
AST::NamedFunctionParam param
= parse_named_function_param (std::move (maybe_variadic_attrs));
if (param.is_error ())
{
Error error (t->get_locus (), "could not parse named function "
"parameter in external function");
add_error (std::move (error));
skip_after_semicolon ();
return nullptr;
}
function_params.push_back (std::move (param));
if (lexer.peek_token ()->get_id () != COMMA)
break;
// skip comma
lexer.skip_token ();
t = lexer.peek_token ();
}
if (!skip_token (RIGHT_PAREN))
{
skip_after_semicolon ();
return nullptr;
}
// parse (optional) return type
std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
// parse (optional) where clause
AST::WhereClause where_clause = parse_where_clause ();
if (!skip_token (SEMICOLON))
{
// skip somewhere?
return nullptr;
}
function_params.shrink_to_fit ();
return std::unique_ptr<AST::ExternalFunctionItem> (
new AST::ExternalFunctionItem (
std::move (ident), std::move (generic_params),
std::move (return_type), std::move (where_clause),
std::move (function_params), is_variadic,
std::move (variadic_attrs), std::move (vis),
std::move (outer_attrs), locus));
}
case FN_TOK:
return parse_external_function_item (std::move (vis),
std::move (outer_attrs));
case TYPE:
return parse_external_type_item (std::move (vis),
std::move (outer_attrs));
@ -6152,56 +6204,6 @@ Parser<ManagedTokenSource>::parse_external_item ()
}
}
/* Parses an extern block function param (with "pattern" being _ or an
* identifier). */
template <typename ManagedTokenSource>
AST::NamedFunctionParam
Parser<ManagedTokenSource>::parse_named_function_param (
AST::AttrVec outer_attrs)
{
// parse identifier/_
std::string name;
const_TokenPtr t = lexer.peek_token ();
location_t name_location = t->get_locus ();
switch (t->get_id ())
{
case IDENTIFIER:
name = t->get_str ();
lexer.skip_token ();
break;
case UNDERSCORE:
name = "_";
lexer.skip_token ();
break;
default:
// this is not a function param, but not necessarily an error
return AST::NamedFunctionParam::create_error ();
}
if (!skip_token (COLON))
{
// skip after somewhere?
return AST::NamedFunctionParam::create_error ();
}
// parse (required) type
std::unique_ptr<AST::Type> param_type = parse_type ();
if (param_type == nullptr)
{
Error error (
lexer.peek_token ()->get_locus (),
"could not parse param type in extern block function declaration");
add_error (std::move (error));
skip_after_semicolon ();
return AST::NamedFunctionParam::create_error ();
}
return AST::NamedFunctionParam (std::move (name), std::move (param_type),
std::move (outer_attrs), name_location);
}
// Parses a statement (will further disambiguate any statement).
template <typename ManagedTokenSource>
std::unique_ptr<AST::Stmt>

View file

@ -298,6 +298,13 @@ private:
AST::Lifetime lifetime_from_token (const_TokenPtr tok);
std::unique_ptr<AST::ExternalTypeItem>
parse_external_type_item (AST::Visibility vis, AST::AttrVec outer_attrs);
std::unique_ptr<AST::ExternalFunctionItem>
parse_external_function_item (AST::Visibility vis, AST::AttrVec outer_attrs);
AST::NamedFunctionParam parse_named_function_param ();
template <typename EndTokenPred>
std::vector<AST::NamedFunctionParam>
parse_named_function_params (EndTokenPred is_end_token);
std::unique_ptr<AST::TypeAlias> parse_type_alias (AST::Visibility vis,
AST::AttrVec outer_attrs);
std::unique_ptr<AST::Struct> parse_struct (AST::Visibility vis,
@ -338,8 +345,6 @@ private:
AST::AttrVec outer_attrs);
std::unique_ptr<AST::ExternBlock>
parse_extern_block (AST::Visibility vis, AST::AttrVec outer_attrs);
AST::NamedFunctionParam parse_named_function_param (AST::AttrVec outer_attrs
= AST::AttrVec ());
AST::Method parse_method ();
// Expression-related (Pratt parsed)

View file

@ -1115,9 +1115,8 @@ ResolveExternItem::visit (AST::ExternalFunctionItem &function)
// we make a new scope so the names of parameters are resolved and shadowed
// correctly
for (auto &param : function.get_function_params ())
{
if (!param.is_variadic ())
ResolveType::go (param.get_type ().get ());
}
// done
resolver->get_name_scope ().pop ();

View file

@ -872,7 +872,8 @@ EarlyNameResolver::visit (AST::ExternalFunctionItem &item)
generic->accept_vis (*this);
for (auto &param : item.get_function_params ())
param.get_type ()->accept_vis (*this);
if (!param.is_variadic ())
param.get_type ()->accept_vis (*this);
if (item.has_return_type ())
item.get_return_type ()->accept_vis (*this);