diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-03-31 08:28:42 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-31 08:28:42 +0000 |
commit | f9c1a14dab4c47c774f9c7661afc4bb2176eb9bb (patch) | |
tree | 3dd88710ab2a9e14b11af931fed15f4637ab4a48 /gcc | |
parent | bd1f435b2310e61ed76d69063004c2aadb496255 (diff) | |
parent | 6bf428379d138f0efe7e72bff11bffa348eb8932 (diff) | |
download | gcc-f9c1a14dab4c47c774f9c7661afc4bb2176eb9bb.zip gcc-f9c1a14dab4c47c774f9c7661afc4bb2176eb9bb.tar.gz gcc-f9c1a14dab4c47c774f9c7661afc4bb2176eb9bb.tar.bz2 |
Merge #1069
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>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-ast.h | 59 | ||||
-rw-r--r-- | gcc/rust/expand/rust-attribute-visitor.cc | 219 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.cc | 16 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro40.rs | 48 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/macros28.rs | 13 |
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> ¶ms) { + expander.push_context (MacroExpander::ContextType::TYPE); + for (auto it = params.begin (); it != params.end ();) { auto ¶m = *it; @@ -98,6 +109,11 @@ AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> ¶ms) 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> ¶ms) // 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 ¶m) 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 ¶m : 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 ¶m : 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 +} |