aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/ast/rust-ast.h59
-rw-r--r--gcc/rust/expand/rust-attribute-visitor.cc219
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc16
-rw-r--r--gcc/rust/expand/rust-macro-expand.h1
-rw-r--r--gcc/testsuite/rust/compile/macro40.rs48
-rw-r--r--gcc/testsuite/rust/execute/torture/macros28.rs13
6 files changed, 344 insertions, 12 deletions
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index a22c2d1..5817a0e 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -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,21 +1879,16 @@ 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
+ std::unique_ptr<Expr> take_expression_fragment ()
{
- return nodes.size () == 1
- && nodes[0].get_kind () == SingleASTNode::NodeType::EXPRESSION;
+ rust_assert (is_single_fragment_kind (SingleASTNode::NodeType::EXPRESSION));
+ return nodes[0].take_expr ();
}
- std::unique_ptr<Expr> take_expression_fragment ()
+ std::unique_ptr<Type> take_type_fragment ()
{
- rust_assert (is_expression_fragment ());
- return nodes[0].take_expr ();
+ rust_assert (is_single_fragment_kind (SingleASTNode::NodeType::TYPE));
+ return nodes[0].take_type ();
}
void accept_vis (ASTVisitor &vis)
diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc
index 8f2a6c7..859ae7e 100644
--- a/gcc/rust/expand/rust-attribute-visitor.cc
+++ b/gcc/rust/expand/rust-attribute-visitor.cc
@@ -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 ())
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 2620fea..852e619 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -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);
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index f08525f..3cac617 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -188,6 +188,7 @@ struct MacroExpander
ITEM,
BLOCK,
EXTERN,
+ TYPE,
TRAIT,
IMPL,
TRAIT_IMPL,
diff --git a/gcc/testsuite/rust/compile/macro40.rs b/gcc/testsuite/rust/compile/macro40.rs
new file mode 100644
index 0000000..7151f3a
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macro40.rs
@@ -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);
+}
diff --git a/gcc/testsuite/rust/execute/torture/macros28.rs b/gcc/testsuite/rust/execute/torture/macros28.rs
new file mode 100644
index 0000000..b011f92
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros28.rs
@@ -0,0 +1,13 @@
+macro_rules! t {
+ () => {
+ i32
+ };
+}
+
+fn id<T>(arg: T) -> T {
+ arg
+}
+
+fn main() -> i32 {
+ id::<t!()>(15) - 15
+}