1069: Handle macro invocations in type contexts r=CohenArthur a=CohenArthur

Closes #1067 

This highlighted two issues where parsing types is not entirely correct, which I'll raise. The code necessary to handle macro invocations in these two places should already be implemented. 

Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
This commit is contained in:
bors[bot] 2022-03-31 08:28:42 +00:00 committed by GitHub
commit f9c1a14dab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 345 additions and 13 deletions

View File

@ -1515,6 +1515,7 @@ public:
TRAIT,
IMPL,
TRAIT_IMPL,
TYPE,
};
private:
@ -1528,6 +1529,7 @@ private:
std::unique_ptr<TraitItem> trait_item;
std::unique_ptr<InherentImplItem> impl_item;
std::unique_ptr<TraitImplItem> trait_impl_item;
std::unique_ptr<Type> type;
public:
SingleASTNode (std::unique_ptr<Expr> expr)
@ -1558,6 +1560,10 @@ public:
: kind (TRAIT_IMPL), trait_impl_item (std::move (trait_impl_item))
{}
SingleASTNode (std::unique_ptr<Type> type)
: kind (TYPE), type (std::move (type))
{}
SingleASTNode (SingleASTNode const &other)
{
kind = other.kind;
@ -1590,6 +1596,10 @@ public:
case TRAIT_IMPL:
trait_impl_item = other.trait_impl_item->clone_trait_impl_item ();
break;
case TYPE:
type = other.type->clone_type ();
break;
}
}
@ -1625,6 +1635,10 @@ public:
case TRAIT_IMPL:
trait_impl_item = other.trait_impl_item->clone_trait_impl_item ();
break;
case TYPE:
type = other.type->clone_type ();
break;
}
return *this;
}
@ -1699,6 +1713,12 @@ public:
return std::move (trait_impl_item);
}
std::unique_ptr<Type> take_type ()
{
rust_assert (!is_error ());
return std::move (type);
}
void accept_vis (ASTVisitor &vis)
{
switch (kind)
@ -1730,6 +1750,10 @@ public:
case TRAIT_IMPL:
trait_impl_item->accept_vis (vis);
break;
case TYPE:
type->accept_vis (vis);
break;
}
}
@ -1751,6 +1775,8 @@ public:
return impl_item == nullptr;
case TRAIT_IMPL:
return trait_impl_item == nullptr;
case TYPE:
return type == nullptr;
}
gcc_unreachable ();
@ -1774,7 +1800,9 @@ public:
case IMPL:
return "Impl Item: " + impl_item->as_string ();
case TRAIT_IMPL:
return "Trait Impl Item: " + impl_item->as_string ();
return "Trait Impl Item: " + trait_impl_item->as_string ();
case TYPE:
return "Type: " + type->as_string ();
}
gcc_unreachable ();
@ -1799,6 +1827,18 @@ private:
std::vector<SingleASTNode> nodes;
bool fragment_is_error;
/**
* We need to make a special case for Expression and Type fragments as only
* one Node will be extracted from the `nodes` vector
*/
bool is_single_fragment () const { return nodes.size () == 1; }
bool is_single_fragment_kind (SingleASTNode::NodeType kind) const
{
return is_single_fragment () && nodes[0].get_kind () == kind;
}
public:
ASTFragment (std::vector<SingleASTNode> nodes, bool fragment_is_error = false)
: nodes (std::move (nodes)), fragment_is_error (fragment_is_error)
@ -1839,23 +1879,18 @@ public:
bool should_expand () const { return !is_error () && !nodes.empty (); }
/**
* We need to make a special case for Expression fragments as only one
* Node will be extracted from the `nodes` vector
*/
bool is_expression_fragment () const
{
return nodes.size () == 1
&& nodes[0].get_kind () == SingleASTNode::NodeType::EXPRESSION;
}
std::unique_ptr<Expr> take_expression_fragment ()
{
rust_assert (is_expression_fragment ());
rust_assert (is_single_fragment_kind (SingleASTNode::NodeType::EXPRESSION));
return nodes[0].take_expr ();
}
std::unique_ptr<Type> take_type_fragment ()
{
rust_assert (is_single_fragment_kind (SingleASTNode::NodeType::TYPE));
return nodes[0].take_type ();
}
void accept_vis (ASTVisitor &vis)
{
for (auto &node : nodes)

View File

@ -35,13 +35,22 @@ AttrVisitor::expand_struct_fields (std::vector<AST::StructField> &fields)
continue;
}
expander.push_context (MacroExpander::ContextType::TYPE);
// expand sub-types of type, but can't strip type itself
auto &type = field.get_field_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
// if nothing else happens, increment
++it;
}
@ -77,6 +86,8 @@ AttrVisitor::expand_tuple_fields (std::vector<AST::TupleField> &fields)
void
AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
{
expander.push_context (MacroExpander::ContextType::TYPE);
for (auto it = params.begin (); it != params.end ();)
{
auto &param = *it;
@ -98,6 +109,11 @@ AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
auto &type = param.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
@ -105,27 +121,40 @@ AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
// increment
++it;
}
expander.pop_context ();
}
void
AttrVisitor::expand_generic_args (AST::GenericArgs &args)
{
// lifetime args can't be expanded
// FIXME: Can we have macro invocations for lifetimes?
expander.push_context (MacroExpander::ContextType::TYPE);
// expand type args - strip sub-types only
for (auto &type : args.get_type_args ())
{
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
}
expander.pop_context ();
// FIXME: Can we have macro invocations in generic type bindings?
// expand binding args - strip sub-types only
for (auto &binding : args.get_binding_args ())
{
auto &type = binding.get_type ();
type->accept_vis (*this);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
@ -135,8 +164,17 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args)
void
AttrVisitor::expand_qualified_path_type (AST::QualifiedPathType &path_type)
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = path_type.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
expander.pop_context ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@ -174,11 +212,19 @@ AttrVisitor::AttrVisitor::expand_closure_params (
if (param.has_type_given ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = param.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
// increment if found nothing else so far
@ -191,11 +237,19 @@ AttrVisitor::expand_self_param (AST::SelfParam &self_param)
{
if (self_param.has_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = self_param.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
/* TODO: maybe check for invariants being violated - e.g. both type and
* lifetime? */
@ -222,11 +276,20 @@ AttrVisitor::expand_trait_function_decl (AST::TraitFunctionDecl &decl)
if (decl.has_return_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &return_type = decl.get_return_type ();
return_type->accept_vis (*this);
auto r_fragment = expander.take_expanded_fragment (*this);
if (r_fragment.should_expand ())
return_type = r_fragment.take_type_fragment ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
if (decl.has_where_clause ())
@ -251,11 +314,20 @@ AttrVisitor::expand_trait_method_decl (AST::TraitMethodDecl &decl)
if (decl.has_return_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &return_type = decl.get_return_type ();
return_type->accept_vis (*this);
auto r_fragment = expander.take_expanded_fragment (*this);
if (r_fragment.should_expand ())
return_type = r_fragment.take_type_fragment ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
if (decl.has_where_clause ())
@ -368,11 +440,20 @@ AttrVisitor::visit (AST::TypePathSegmentFunction &segment)
if (type_path_function.has_return_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &return_type = type_path_function.get_return_type ();
return_type->accept_vis (*this);
auto r_fragment = expander.take_expanded_fragment (*this);
if (r_fragment.should_expand ())
return_type = r_fragment.take_type_fragment ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
}
void
@ -1176,12 +1257,21 @@ AttrVisitor::visit (AST::ClosureExprInnerTyped &expr)
* allowed by spec */
expand_closure_params (expr.get_params ());
expander.push_context (MacroExpander::ContextType::TYPE);
// can't strip return type, but can strip sub-types
auto &type = expr.get_return_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
// can't strip expression itself, but can strip sub-expressions
auto &definition_block = expr.get_definition_block ();
definition_block->accept_vis (*this);
@ -1928,11 +2018,19 @@ AttrVisitor::visit (AST::TypeParam &param)
if (param.has_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = param.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
}
void
@ -1945,11 +2043,20 @@ AttrVisitor::visit (AST::TypeBoundWhereClauseItem &item)
{
// for lifetimes shouldn't require
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = item.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
// don't strip directly, only components of bounds
for (auto &bound : item.get_type_param_bounds ())
bound->accept_vis (*this);
@ -1980,11 +2087,20 @@ AttrVisitor::visit (AST::Method &method)
if (method.has_return_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &return_type = method.get_return_type ();
return_type->accept_vis (*this);
auto r_fragment = expander.take_expanded_fragment (*this);
if (r_fragment.should_expand ())
return_type = r_fragment.take_type_fragment ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
if (method.has_where_clause ())
@ -2093,11 +2209,20 @@ AttrVisitor::visit (AST::Function &function)
if (function.has_return_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &return_type = function.get_return_type ();
return_type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
return_type = t_fragment.take_type_fragment ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
if (function.has_where_clause ())
@ -2297,12 +2422,21 @@ AttrVisitor::visit (AST::ConstantItem &const_item)
return;
}
expander.push_context (MacroExpander::ContextType::TYPE);
// strip any sub-types
auto &type = const_item.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
@ -2324,12 +2458,21 @@ AttrVisitor::visit (AST::StaticItem &static_item)
return;
}
expander.push_context (MacroExpander::ContextType::TYPE);
// strip any sub-types
auto &type = static_item.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped. */
@ -2403,12 +2546,21 @@ AttrVisitor::visit (AST::TraitItemConst &item)
return;
}
expander.push_context (MacroExpander::ContextType::TYPE);
// strip any sub-types
auto &type = item.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
/* strip any internal sub-expressions - expression itself isn't
* allowed to have external attributes in this position so can't be
* stripped */
@ -2502,11 +2654,20 @@ AttrVisitor::visit (AST::InherentImpl &impl)
for (auto &param : impl.get_generic_params ())
param->accept_vis (*this);
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = impl.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
if (impl.has_where_clause ())
expand_where_clause (impl.get_where_clause ());
@ -2539,11 +2700,20 @@ AttrVisitor::visit (AST::TraitImpl &impl)
for (auto &param : impl.get_generic_params ())
param->accept_vis (*this);
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = impl.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
auto &trait_path = impl.get_trait_path ();
visit (trait_path);
if (trait_path.is_marked_for_strip ())
@ -2571,10 +2741,19 @@ AttrVisitor::visit (AST::ExternalStaticItem &item)
return;
}
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = item.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
expander.pop_context ();
}
void
AttrVisitor::visit (AST::ExternalFunctionItem &item)
@ -2606,12 +2785,21 @@ AttrVisitor::visit (AST::ExternalFunctionItem &item)
continue;
}
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = param.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
// increment if nothing else happens
++it;
}
@ -2624,16 +2812,26 @@ AttrVisitor::visit (AST::ExternalFunctionItem &item)
if (item.has_return_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &return_type = item.get_return_type ();
return_type->accept_vis (*this);
auto r_fragment = expander.take_expanded_fragment (*this);
if (r_fragment.should_expand ())
return_type = r_fragment.take_type_fragment ();
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
if (item.has_where_clause ())
expand_where_clause (item.get_where_clause ());
}
void
AttrVisitor::visit (AST::ExternBlock &block)
{
@ -2991,11 +3189,20 @@ AttrVisitor::visit (AST::LetStmt &stmt)
// similar for type
if (stmt.has_type ())
{
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = stmt.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
}
/* strip any internal sub-expressions - expression itself isn't
@ -3190,12 +3397,21 @@ AttrVisitor::visit (AST::BareFunctionType &type)
continue;
}
expander.push_context (MacroExpander::ContextType::TYPE);
auto &type = param.get_type ();
type->accept_vis (*this);
auto t_fragment = expander.take_expanded_fragment (*this);
if (t_fragment.should_expand ())
type = t_fragment.take_type_fragment ();
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
"cannot strip type in this position");
expander.pop_context ();
// increment if nothing else happens
++it;
}
@ -3205,6 +3421,9 @@ AttrVisitor::visit (AST::BareFunctionType &type)
if (type.has_return_type ())
{
// FIXME: Can we have type expansion in this position?
// In that case, we need to handle AST::TypeNoBounds on top of just
// AST::Types
auto &return_type = type.get_return_type ();
return_type->accept_vis (*this);
if (return_type->is_marked_for_strip ())

View File

@ -909,6 +909,19 @@ transcribe_expression (Parser<MacroInvocLexer> &parser)
return {AST::SingleASTNode (std::move (expr))};
}
/**
* Transcribe one type from a macro invocation
*
* @param parser Parser to extract statements from
*/
static std::vector<AST::SingleASTNode>
transcribe_type (Parser<MacroInvocLexer> &parser)
{
auto expr = parser.parse_type ();
return {AST::SingleASTNode (std::move (expr))};
}
static std::vector<AST::SingleASTNode>
transcribe_on_delimiter (Parser<MacroInvocLexer> &parser, bool semicolon,
AST::DelimType delimiter, TokenId last_token_id)
@ -957,6 +970,9 @@ transcribe_context (MacroExpander::ContextType ctx,
case MacroExpander::ContextType::EXTERN:
return transcribe_many_ext (parser, last_token_id);
break;
case MacroExpander::ContextType::TYPE:
return transcribe_type (parser);
break;
default:
return transcribe_on_delimiter (parser, semicolon, delimiter,
last_token_id);

View File

@ -188,6 +188,7 @@ struct MacroExpander
ITEM,
BLOCK,
EXTERN,
TYPE,
TRAIT,
IMPL,
TRAIT_IMPL,

View File

@ -0,0 +1,48 @@
// { dg-additional-options "-w" }
macro_rules! t {
() => {
i32
};
}
macro_rules! s {
() => {
*const i8
};
}
extern "C" {
fn printf(s: s!(), ...);
}
fn square(arg: t!()) -> t!() {
let input: t!() = arg;
input * input
}
trait Trait {
fn f() -> t!();
fn g(arg: t!());
}
struct Wrapper {
inner: t!(),
}
impl Trait for Wrapper {
fn f() -> t!() {
1
}
fn g(arg: t!()) {}
}
fn id<T>(arg: T) -> T {
arg
}
fn main() {
id::<t!()>(15);
}

View File

@ -0,0 +1,13 @@
macro_rules! t {
() => {
i32
};
}
fn id<T>(arg: T) -> T {
arg
}
fn main() -> i32 {
id::<t!()>(15) - 15
}