gccrs: expansion: Desugar doc comments into attributes before expansion
gcc/rust/ChangeLog: * expand/rust-macro-expand.cc (MacroExpander::expand_decl_macro): Call into TokenTreeDesugar. * expand/rust-token-tree-desugar.cc: New file. * expand/rust-token-tree-desugar.h: New file. * Make-lang.in: Compile them. gcc/testsuite/ChangeLog: * rust/compile/macros/mbe/macro-issue3709-1.rs: New test. * rust/compile/macros/mbe/macro-issue3709-2.rs: New test.
This commit is contained in:
parent
cb23182fa2
commit
9710cf3e34
7 changed files with 234 additions and 1 deletions
|
@ -115,6 +115,7 @@ GRS_OBJS = \
|
|||
rust/rust-macro-builtins-format-args.o \
|
||||
rust/rust-macro-builtins-location.o \
|
||||
rust/rust-macro-builtins-include.o \
|
||||
rust/rust-token-tree-desugar.o \
|
||||
rust/rust-fmt.o \
|
||||
rust/rust-hir.o \
|
||||
rust/rust-hir-map.o \
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "rust-cfg-strip.h"
|
||||
#include "rust-early-name-resolver.h"
|
||||
#include "rust-proc-macro.h"
|
||||
#include "rust-token-tree-desugar.h"
|
||||
|
||||
namespace Rust {
|
||||
|
||||
|
@ -78,7 +79,10 @@ MacroExpander::expand_decl_macro (location_t invoc_locus,
|
|||
* trees.
|
||||
*/
|
||||
|
||||
AST::DelimTokenTree &invoc_token_tree = invoc.get_delim_tok_tree ();
|
||||
AST::DelimTokenTree &invoc_token_tree_sugar = invoc.get_delim_tok_tree ();
|
||||
|
||||
// We must first desugar doc comments into proper attributes
|
||||
auto invoc_token_tree = AST::TokenTreeDesugar ().go (invoc_token_tree_sugar);
|
||||
|
||||
// find matching arm
|
||||
AST::MacroRule *matched_rule = nullptr;
|
||||
|
|
72
gcc/rust/expand/rust-token-tree-desugar.cc
Normal file
72
gcc/rust/expand/rust-token-tree-desugar.cc
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "rust-token-tree-desugar.h"
|
||||
#include "rust-ast.h"
|
||||
#include "rust-token.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace AST {
|
||||
|
||||
DelimTokenTree
|
||||
TokenTreeDesugar::go (DelimTokenTree &tts)
|
||||
{
|
||||
tts.accept_vis (*this);
|
||||
|
||||
return DelimTokenTree (tts.get_delim_type (), std::move (desugared),
|
||||
tts.get_locus ());
|
||||
}
|
||||
|
||||
void
|
||||
TokenTreeDesugar::append (TokenPtr &&new_token)
|
||||
{
|
||||
desugared.emplace_back (std::make_unique<Token> (std::move (new_token)));
|
||||
}
|
||||
|
||||
void
|
||||
TokenTreeDesugar::append (std::unique_ptr<TokenTree> &&new_token)
|
||||
{
|
||||
desugared.emplace_back (std::move (new_token));
|
||||
}
|
||||
|
||||
void
|
||||
TokenTreeDesugar::visit (Token &tts)
|
||||
{
|
||||
if (tts.get_id () == TokenId::OUTER_DOC_COMMENT
|
||||
|| tts.get_id () == TokenId::INNER_DOC_COMMENT)
|
||||
{
|
||||
append (Rust::Token::make (TokenId::HASH, tts.get_locus ()));
|
||||
|
||||
if (tts.get_id () == TokenId::INNER_DOC_COMMENT)
|
||||
append (Rust::Token::make (EXCLAM, tts.get_locus ()));
|
||||
|
||||
append (Rust::Token::make (TokenId::LEFT_SQUARE, tts.get_locus ()));
|
||||
append (Rust::Token::make_identifier (tts.get_locus (), "doc"));
|
||||
append (Rust::Token::make (TokenId::EQUAL, tts.get_locus ()));
|
||||
append (Rust::Token::make_string (tts.get_locus (),
|
||||
std::string (tts.get_str ())));
|
||||
append (Rust::Token::make (TokenId::RIGHT_SQUARE, tts.get_locus ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
append (tts.clone_token ());
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace AST
|
||||
}; // namespace Rust
|
55
gcc/rust/expand/rust-token-tree-desugar.h
Normal file
55
gcc/rust/expand/rust-token-tree-desugar.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef RUST_TOKEN_TREE_DESUGAR_H
|
||||
#define RUST_TOKEN_TREE_DESUGAR_H
|
||||
|
||||
#include "rust-ast-visitor.h"
|
||||
#include "rust-system.h"
|
||||
#include "rust-ast.h"
|
||||
|
||||
namespace Rust {
|
||||
namespace AST {
|
||||
|
||||
/**
|
||||
* Desugar a given token-tree before parsing it for a macro invocation. At the
|
||||
* moment, the sole purpose of this desugar is to transform doc-comments into
|
||||
* their attribute form (/// comment -> #[doc = "comment"])
|
||||
*/
|
||||
class TokenTreeDesugar : public DefaultASTVisitor
|
||||
{
|
||||
public:
|
||||
TokenTreeDesugar () : desugared (std::vector<std::unique_ptr<TokenTree>> ())
|
||||
{}
|
||||
|
||||
DelimTokenTree go (DelimTokenTree &tts);
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<TokenTree>> desugared;
|
||||
void append (TokenPtr &&new_token);
|
||||
void append (std::unique_ptr<TokenTree> &&new_token);
|
||||
|
||||
using DefaultASTVisitor::visit;
|
||||
|
||||
virtual void visit (Token &tts) override;
|
||||
};
|
||||
|
||||
}; // namespace AST
|
||||
}; // namespace Rust
|
||||
|
||||
#endif //! RUST_TOKEN_TREE_DESUGAR_H
|
10
gcc/testsuite/rust/compile/macros/mbe/macro-issue3693.rs
Normal file
10
gcc/testsuite/rust/compile/macros/mbe/macro-issue3693.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
macro_rules! generate_pattern_iterators {
|
||||
{
|
||||
$(#[$forward_iterator_attribute:meta])*
|
||||
} => {
|
||||
}
|
||||
}
|
||||
|
||||
generate_pattern_iterators! {
|
||||
/// Created with the method [`split`].
|
||||
}
|
10
gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-1.rs
Normal file
10
gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-1.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
macro_rules! doc_comment {
|
||||
(#[ $attr: meta ]) => {
|
||||
#[$attr]
|
||||
struct Generated; // { dg-warning "never constructed" }
|
||||
};
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
/// This is a generated struct
|
||||
}
|
81
gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs
Normal file
81
gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" }
|
||||
|
||||
macro_rules! impl_fn_for_zst {
|
||||
($(
|
||||
$( #[$attr: meta] )*
|
||||
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
|
||||
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
|
||||
$body: block;
|
||||
)+) => {
|
||||
$(
|
||||
$( #[$attr] )*
|
||||
struct $Name;
|
||||
|
||||
impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
|
||||
#[inline]
|
||||
extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
|
||||
$body
|
||||
}
|
||||
}
|
||||
|
||||
impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
|
||||
#[inline]
|
||||
extern "rust-call" fn call_mut(
|
||||
&mut self,
|
||||
($( $arg, )*): ($( $ArgTy, )*)
|
||||
) -> $ReturnTy {
|
||||
Fn::call(&*self, ($( $arg, )*))
|
||||
}
|
||||
}
|
||||
|
||||
impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
|
||||
type Output = $ReturnTy;
|
||||
|
||||
#[inline]
|
||||
extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
|
||||
Fn::call(&self, ($( $arg, )*))
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
#[lang = "fn"]
|
||||
pub trait Fn<Args>: FnMut<Args> {
|
||||
/// Performs the call operation.
|
||||
#[unstable(feature = "fn_traits", issue = "29625")]
|
||||
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
#[lang = "fn_mut"]
|
||||
#[must_use = "closures are lazy and do nothing unless called"]
|
||||
pub trait FnMut<Args>: FnOnce<Args> {
|
||||
/// Performs the call operation.
|
||||
#[unstable(feature = "fn_traits", issue = "29625")]
|
||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
#[lang = "fn_once"]
|
||||
pub trait FnOnce<Args> {
|
||||
/// The returned type after the call operator is used.
|
||||
#[lang = "fn_once_output"]
|
||||
#[stable(feature = "fn_once_output", since = "1.12.0")]
|
||||
type Output;
|
||||
|
||||
/// Performs the call operation.
|
||||
#[unstable(feature = "fn_traits", issue = "29625")]
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
impl_fn_for_zst! {
|
||||
/// Documentation for the zst
|
||||
#[derive(Copy)]
|
||||
struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> () {
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue