Implement span quoting for proc-macros
This PR implements span quoting, allowing proc-macros to produce spans pointing *into their own crate*. This is used by the unstable `proc_macro::quote!` macro, allowing us to get error messages like this: ``` error[E0412]: cannot find type `MissingType` in this scope --> $DIR/auxiliary/span-from-proc-macro.rs:37:20 | LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream { | ----------------------------------------------------------------------------------- in this expansion of procedural macro `#[error_from_attribute]` ... LL | field: MissingType | ^^^^^^^^^^^ not found in this scope | ::: $DIR/span-from-proc-macro.rs:8:1 | LL | #[error_from_attribute] | ----------------------- in this macro invocation ``` Here, `MissingType` occurs inside the implementation of the proc-macro `#[error_from_attribute]`. Previosuly, this would always result in a span pointing at `#[error_from_attribute]` This will make many proc-macro-related error message much more useful - when a proc-macro generates code containing an error, users will get an error message pointing directly at that code (within the macro definition), instead of always getting a span pointing at the macro invocation site. This is implemented as follows: * When a proc-macro crate is being *compiled*, it causes the `quote!` macro to get run. This saves all of the sapns in the input to `quote!` into the metadata of *the proc-macro-crate* (which we are currently compiling). The `quote!` macro then expands to a call to `proc_macro::Span::recover_proc_macro_span(id)`, where `id` is an opaque identifier for the span in the crate metadata. * When the same proc-macro crate is *run* (e.g. it is loaded from disk and invoked by some consumer crate), the call to `proc_macro::Span::recover_proc_macro_span` causes us to load the span from the proc-macro crate's metadata. The proc-macro then produces a `TokenStream` containing a `Span` pointing into the proc-macro crate itself. The recursive nature of 'quote!' can be difficult to understand at first. The file `src/test/ui/proc-macro/quote-debug.stdout` shows the output of the `quote!` macro, which should make this eaier to understand. This PR also supports custom quoting spans in custom quote macros (e.g. the `quote` crate). All span quoting goes through the `proc_macro::quote_span` method, which can be called by a custom quote macro to perform span quoting. An example of this usage is provided in `src/test/ui/proc-macro/auxiliary/custom-quote.rs` Custom quoting currently has a few limitations: In order to quote a span, we need to generate a call to `proc_macro::Span::recover_proc_macro_span`. However, proc-macros support renaming the `proc_macro` crate, so we can't simply hardcode this path. Previously, the `quote_span` method used the path `crate::Span` - however, this only works when it is called by the builtin `quote!` macro in the same crate. To support being called from arbitrary crates, we need access to the name of the `proc_macro` crate to generate a path. This PR adds an additional argument to `quote_span` to specify the name of the `proc_macro` crate. Howver, this feels kind of hacky, and we may want to change this before stabilizing anything quote-related. Additionally, using `quote_span` currently requires enabling the `proc_macro_internals` feature. The builtin `quote!` macro has an `#[allow_internal_unstable]` attribute, but this won't work for custom quote implementations. This will likely require some additional tricks to apply `allow_internal_unstable` to the span of `proc_macro::Span::recover_proc_macro_span`.
This commit is contained in:
parent
ea3068efe4
commit
f916b0474a
34 changed files with 494 additions and 69 deletions
|
@ -20,6 +20,7 @@ use crate::deriving::*;
|
||||||
|
|
||||||
use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
|
use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
|
||||||
use rustc_expand::proc_macro::BangProcMacro;
|
use rustc_expand::proc_macro::BangProcMacro;
|
||||||
|
use rustc_span::def_id::LOCAL_CRATE;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
mod asm;
|
mod asm;
|
||||||
|
@ -114,5 +115,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
||||||
register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
|
register(
|
||||||
|
sym::quote,
|
||||||
|
SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client, krate: LOCAL_CRATE })),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,7 +309,9 @@ pub trait Emitter {
|
||||||
// are some which do actually involve macros.
|
// are some which do actually involve macros.
|
||||||
ExpnKind::Inlined | ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None,
|
ExpnKind::Inlined | ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None,
|
||||||
|
|
||||||
ExpnKind::Macro(macro_kind, _) => Some(macro_kind),
|
ExpnKind::Macro { kind: macro_kind, name: _, proc_macro: _ } => {
|
||||||
|
Some(macro_kind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -371,10 +373,19 @@ pub trait Emitter {
|
||||||
new_labels
|
new_labels
|
||||||
.push((trace.call_site, "in the inlined copy of this code".to_string()));
|
.push((trace.call_site, "in the inlined copy of this code".to_string()));
|
||||||
} else if always_backtrace {
|
} else if always_backtrace {
|
||||||
|
let proc_macro = if let ExpnKind::Macro { kind: _, name: _, proc_macro: true } =
|
||||||
|
trace.kind
|
||||||
|
{
|
||||||
|
"procedural macro "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
new_labels.push((
|
new_labels.push((
|
||||||
trace.def_site,
|
trace.def_site,
|
||||||
format!(
|
format!(
|
||||||
"in this expansion of `{}`{}",
|
"in this expansion of {}`{}`{}",
|
||||||
|
proc_macro,
|
||||||
trace.kind.descr(),
|
trace.kind.descr(),
|
||||||
if macro_backtrace.len() > 1 {
|
if macro_backtrace.len() > 1 {
|
||||||
// if macro_backtrace.len() == 1 it'll be
|
// if macro_backtrace.len() == 1 it'll be
|
||||||
|
@ -400,7 +411,11 @@ pub trait Emitter {
|
||||||
// and it needs an "in this macro invocation" label to match that.
|
// and it needs an "in this macro invocation" label to match that.
|
||||||
let redundant_span = trace.call_site.contains(sp);
|
let redundant_span = trace.call_site.contains(sp);
|
||||||
|
|
||||||
if !redundant_span && matches!(trace.kind, ExpnKind::Macro(MacroKind::Bang, _))
|
if !redundant_span
|
||||||
|
&& matches!(
|
||||||
|
trace.kind,
|
||||||
|
ExpnKind::Macro { kind: MacroKind::Bang, name: _, proc_macro: _ }
|
||||||
|
)
|
||||||
|| always_backtrace
|
|| always_backtrace
|
||||||
{
|
{
|
||||||
new_labels.push((
|
new_labels.push((
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
|
||||||
use rustc_lint_defs::BuiltinLintDiagnostics;
|
use rustc_lint_defs::BuiltinLintDiagnostics;
|
||||||
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
|
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
|
||||||
use rustc_session::{parse::ParseSess, Limit, Session};
|
use rustc_session::{parse::ParseSess, Limit, Session};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::{CrateNum, DefId};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
|
use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
|
@ -810,8 +810,16 @@ impl SyntaxExtension {
|
||||||
descr: Symbol,
|
descr: Symbol,
|
||||||
macro_def_id: Option<DefId>,
|
macro_def_id: Option<DefId>,
|
||||||
) -> ExpnData {
|
) -> ExpnData {
|
||||||
|
use SyntaxExtensionKind::*;
|
||||||
|
let proc_macro = match self.kind {
|
||||||
|
// User-defined proc macro
|
||||||
|
Bang(..) | Attr(..) | Derive(..) => true,
|
||||||
|
// Consider everthing else to be not a proc
|
||||||
|
// macro for diagnostic purposes
|
||||||
|
LegacyBang(..) | LegacyAttr(..) | NonMacroAttr { .. } | LegacyDerive(..) => false,
|
||||||
|
};
|
||||||
ExpnData::new(
|
ExpnData::new(
|
||||||
ExpnKind::Macro(self.macro_kind(), descr),
|
ExpnKind::Macro { kind: self.macro_kind(), name: descr, proc_macro },
|
||||||
parent,
|
parent,
|
||||||
call_site,
|
call_site,
|
||||||
self.span,
|
self.span,
|
||||||
|
@ -873,6 +881,10 @@ pub trait ResolverExpand {
|
||||||
fn take_derive_resolutions(&mut self, expn_id: ExpnId) -> Option<DeriveResolutions>;
|
fn take_derive_resolutions(&mut self, expn_id: ExpnId) -> Option<DeriveResolutions>;
|
||||||
/// Path resolution logic for `#[cfg_accessible(path)]`.
|
/// Path resolution logic for `#[cfg_accessible(path)]`.
|
||||||
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
|
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
|
||||||
|
|
||||||
|
/// Decodes the proc-macro quoted span in the specified crate, with the specified id.
|
||||||
|
/// No caching is performed.
|
||||||
|
fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
|
|
@ -9,12 +9,14 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_parse::nt_to_tokenstream;
|
use rustc_parse::nt_to_tokenstream;
|
||||||
use rustc_parse::parser::ForceCollect;
|
use rustc_parse::parser::ForceCollect;
|
||||||
|
use rustc_span::def_id::CrateNum;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
|
const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
|
||||||
|
|
||||||
pub struct BangProcMacro {
|
pub struct BangProcMacro {
|
||||||
pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
|
pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
|
||||||
|
pub krate: CrateNum,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl base::ProcMacro for BangProcMacro {
|
impl base::ProcMacro for BangProcMacro {
|
||||||
|
@ -24,7 +26,7 @@ impl base::ProcMacro for BangProcMacro {
|
||||||
span: Span,
|
span: Span,
|
||||||
input: TokenStream,
|
input: TokenStream,
|
||||||
) -> Result<TokenStream, ErrorReported> {
|
) -> Result<TokenStream, ErrorReported> {
|
||||||
let server = proc_macro_server::Rustc::new(ecx);
|
let server = proc_macro_server::Rustc::new(ecx, self.krate);
|
||||||
self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| {
|
self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| {
|
||||||
let mut err = ecx.struct_span_err(span, "proc macro panicked");
|
let mut err = ecx.struct_span_err(span, "proc macro panicked");
|
||||||
if let Some(s) = e.as_str() {
|
if let Some(s) = e.as_str() {
|
||||||
|
@ -38,6 +40,7 @@ impl base::ProcMacro for BangProcMacro {
|
||||||
|
|
||||||
pub struct AttrProcMacro {
|
pub struct AttrProcMacro {
|
||||||
pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
|
pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
|
||||||
|
pub krate: CrateNum,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl base::AttrProcMacro for AttrProcMacro {
|
impl base::AttrProcMacro for AttrProcMacro {
|
||||||
|
@ -48,7 +51,7 @@ impl base::AttrProcMacro for AttrProcMacro {
|
||||||
annotation: TokenStream,
|
annotation: TokenStream,
|
||||||
annotated: TokenStream,
|
annotated: TokenStream,
|
||||||
) -> Result<TokenStream, ErrorReported> {
|
) -> Result<TokenStream, ErrorReported> {
|
||||||
let server = proc_macro_server::Rustc::new(ecx);
|
let server = proc_macro_server::Rustc::new(ecx, self.krate);
|
||||||
self.client
|
self.client
|
||||||
.run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace)
|
.run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
@ -64,6 +67,7 @@ impl base::AttrProcMacro for AttrProcMacro {
|
||||||
|
|
||||||
pub struct ProcMacroDerive {
|
pub struct ProcMacroDerive {
|
||||||
pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
|
pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
|
||||||
|
pub krate: CrateNum,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultiItemModifier for ProcMacroDerive {
|
impl MultiItemModifier for ProcMacroDerive {
|
||||||
|
@ -97,7 +101,7 @@ impl MultiItemModifier for ProcMacroDerive {
|
||||||
nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
|
nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
|
||||||
};
|
};
|
||||||
|
|
||||||
let server = proc_macro_server::Rustc::new(ecx);
|
let server = proc_macro_server::Rustc::new(ecx, self.krate);
|
||||||
let stream =
|
let stream =
|
||||||
match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) {
|
match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) {
|
||||||
Ok(stream) => stream,
|
Ok(stream) => stream,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::base::ExtCtxt;
|
use crate::base::{ExtCtxt, ResolverExpand};
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::token;
|
use rustc_ast::token;
|
||||||
|
@ -7,6 +7,7 @@ use rustc_ast::token::NtIdent;
|
||||||
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
|
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
|
||||||
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
|
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::Diagnostic;
|
use rustc_errors::Diagnostic;
|
||||||
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
|
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
|
||||||
|
@ -14,6 +15,8 @@ use rustc_lint_defs::BuiltinLintDiagnostics;
|
||||||
use rustc_parse::lexer::nfc_normalize;
|
use rustc_parse::lexer::nfc_normalize;
|
||||||
use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
|
use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
|
use rustc_span::def_id::CrateNum;
|
||||||
|
use rustc_span::hygiene::ExpnId;
|
||||||
use rustc_span::hygiene::ExpnKind;
|
use rustc_span::hygiene::ExpnKind;
|
||||||
use rustc_span::symbol::{self, kw, sym, Symbol};
|
use rustc_span::symbol::{self, kw, sym, Symbol};
|
||||||
use rustc_span::{BytePos, FileName, MultiSpan, Pos, RealFileName, SourceFile, Span};
|
use rustc_span::{BytePos, FileName, MultiSpan, Pos, RealFileName, SourceFile, Span};
|
||||||
|
@ -355,22 +358,34 @@ pub struct Literal {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Rustc<'a> {
|
pub(crate) struct Rustc<'a> {
|
||||||
|
resolver: &'a dyn ResolverExpand,
|
||||||
sess: &'a ParseSess,
|
sess: &'a ParseSess,
|
||||||
def_site: Span,
|
def_site: Span,
|
||||||
call_site: Span,
|
call_site: Span,
|
||||||
mixed_site: Span,
|
mixed_site: Span,
|
||||||
span_debug: bool,
|
span_debug: bool,
|
||||||
|
krate: CrateNum,
|
||||||
|
expn_id: ExpnId,
|
||||||
|
rebased_spans: FxHashMap<usize, Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Rustc<'a> {
|
impl<'a> Rustc<'a> {
|
||||||
pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
|
pub fn new(cx: &'a ExtCtxt<'_>, krate: CrateNum) -> Self {
|
||||||
let expn_data = cx.current_expansion.id.expn_data();
|
let expn_data = cx.current_expansion.id.expn_data();
|
||||||
|
let def_site = cx.with_def_site_ctxt(expn_data.def_site);
|
||||||
|
let call_site = cx.with_call_site_ctxt(expn_data.call_site);
|
||||||
|
let mixed_site = cx.with_mixed_site_ctxt(expn_data.call_site);
|
||||||
|
let sess = cx.parse_sess();
|
||||||
Rustc {
|
Rustc {
|
||||||
sess: &cx.sess.parse_sess,
|
resolver: cx.resolver,
|
||||||
def_site: cx.with_def_site_ctxt(expn_data.def_site),
|
sess,
|
||||||
call_site: cx.with_call_site_ctxt(expn_data.call_site),
|
def_site,
|
||||||
mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
|
call_site,
|
||||||
|
mixed_site,
|
||||||
span_debug: cx.ecfg.span_debug,
|
span_debug: cx.ecfg.span_debug,
|
||||||
|
krate,
|
||||||
|
expn_id: cx.current_expansion.id,
|
||||||
|
rebased_spans: FxHashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,6 +728,51 @@ impl server::Span for Rustc<'_> {
|
||||||
fn source_text(&mut self, span: Self::Span) -> Option<String> {
|
fn source_text(&mut self, span: Self::Span) -> Option<String> {
|
||||||
self.sess.source_map().span_to_snippet(span).ok()
|
self.sess.source_map().span_to_snippet(span).ok()
|
||||||
}
|
}
|
||||||
|
/// Saves the provided span into the metadata of
|
||||||
|
/// *the crate we are currently compiling*, which must
|
||||||
|
/// be a proc-macro crate. This id can be passed to
|
||||||
|
/// `recover_proc_macro_span` when our current crate
|
||||||
|
/// is *run* as a proc-macro.
|
||||||
|
///
|
||||||
|
/// Let's suppose that we have two crates - `my_client`
|
||||||
|
/// and `my_proc_macro`. The `my_proc_macro` crate
|
||||||
|
/// contains a procedural macro `my_macro`, which
|
||||||
|
/// is implemented as: `quote! { "hello" }`
|
||||||
|
///
|
||||||
|
/// When we *compile* `my_proc_macro`, we will execute
|
||||||
|
/// the `quote` proc-macro. This will save the span of
|
||||||
|
/// "hello" into the metadata of `my_proc_macro`. As a result,
|
||||||
|
/// the body of `my_proc_macro` (after expansion) will end
|
||||||
|
/// up containg a call that looks like this:
|
||||||
|
/// `proc_macro::Ident::new("hello", proc_macro::Span::recover_proc_macro_span(0))`
|
||||||
|
///
|
||||||
|
/// where `0` is the id returned by this function.
|
||||||
|
/// When `my_proc_macro` *executes* (during the compilation of `my_client`),
|
||||||
|
/// the call to `recover_proc_macro_span` will load the corresponding
|
||||||
|
/// span from the metadata of `my_proc_macro` (which we have access to,
|
||||||
|
/// since we've loaded `my_proc_macro` from disk in order to execute it).
|
||||||
|
/// In this way, we have obtained a span pointing into `my_proc_macro`
|
||||||
|
fn save_span(&mut self, mut span: Self::Span) -> usize {
|
||||||
|
// Throw away the `SyntaxContext`, since we currently
|
||||||
|
// skip serializing `SyntaxContext`s for proc-macro crates
|
||||||
|
span = span.with_ctxt(rustc_span::SyntaxContext::root());
|
||||||
|
self.sess.save_proc_macro_span(span)
|
||||||
|
}
|
||||||
|
fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
|
||||||
|
let resolver = self.resolver;
|
||||||
|
let krate = self.krate;
|
||||||
|
let expn_id = self.expn_id;
|
||||||
|
*self.rebased_spans.entry(id).or_insert_with(|| {
|
||||||
|
let raw_span = resolver.get_proc_macro_quoted_span(krate, id);
|
||||||
|
// Ignore the deserialized `SyntaxContext` entirely.
|
||||||
|
// FIXME: Preserve the macro backtrace from the serialized span
|
||||||
|
// For example, if a proc-macro crate has code like
|
||||||
|
// `macro_one!() -> macro_two!() -> quote!()`, we might
|
||||||
|
// want to 'concatenate' this backtrace with the backtrace from
|
||||||
|
// our current call site.
|
||||||
|
raw_span.with_def_site_ctxt(expn_id)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See issue #74616 for details
|
// See issue #74616 for details
|
||||||
|
@ -722,7 +782,7 @@ fn ident_name_compatibility_hack(
|
||||||
rustc: &mut Rustc<'_>,
|
rustc: &mut Rustc<'_>,
|
||||||
) -> Option<(rustc_span::symbol::Ident, bool)> {
|
) -> Option<(rustc_span::symbol::Ident, bool)> {
|
||||||
if let NtIdent(ident, is_raw) = nt {
|
if let NtIdent(ident, is_raw) = nt {
|
||||||
if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
|
if let ExpnKind::Macro { name: macro_name, .. } = orig_span.ctxt().outer_expn_data().kind {
|
||||||
let source_map = rustc.sess.source_map();
|
let source_map = rustc.sess.source_map();
|
||||||
let filename = source_map.span_to_filename(orig_span);
|
let filename = source_map.span_to_filename(orig_span);
|
||||||
if let FileName::Real(RealFileName::Named(path)) = filename {
|
if let FileName::Real(RealFileName::Named(path)) = filename {
|
||||||
|
|
|
@ -248,10 +248,21 @@ impl EarlyLintPass for LintPassImpl {
|
||||||
if last.ident.name == sym::LintPass {
|
if last.ident.name == sym::LintPass {
|
||||||
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
|
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
|
||||||
let call_site = expn_data.call_site;
|
let call_site = expn_data.call_site;
|
||||||
if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
|
if !matches!(
|
||||||
&& call_site.ctxt().outer_expn_data().kind
|
expn_data.kind,
|
||||||
!= ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
|
ExpnKind::Macro {
|
||||||
{
|
kind: MacroKind::Bang,
|
||||||
|
name: sym::impl_lint_pass,
|
||||||
|
proc_macro: _
|
||||||
|
}
|
||||||
|
) && !matches!(
|
||||||
|
call_site.ctxt().outer_expn_data().kind,
|
||||||
|
ExpnKind::Macro {
|
||||||
|
kind: MacroKind::Bang,
|
||||||
|
name: sym::declare_lint_pass,
|
||||||
|
proc_macro: _
|
||||||
|
}
|
||||||
|
) {
|
||||||
cx.struct_span_lint(
|
cx.struct_span_lint(
|
||||||
LINT_PASS_IMPL_WITHOUT_MACRO,
|
LINT_PASS_IMPL_WITHOUT_MACRO,
|
||||||
lint_pass.path.span,
|
lint_pass.path.span,
|
||||||
|
|
|
@ -248,10 +248,11 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let macro_symbol = if let hygiene::ExpnKind::Macro(_, symbol) = expn.kind {
|
let macro_symbol =
|
||||||
symbol
|
if let hygiene::ExpnKind::Macro { kind: _, name: symbol, proc_macro: _ } = expn.kind {
|
||||||
} else {
|
symbol
|
||||||
Symbol::intern("panic")
|
} else {
|
||||||
};
|
Symbol::intern("panic")
|
||||||
|
};
|
||||||
(expn.call_site, panic_macro, macro_symbol.as_str())
|
(expn.call_site, panic_macro, macro_symbol.as_str())
|
||||||
}
|
}
|
||||||
|
|
|
@ -716,30 +716,37 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
.decode((self, sess))
|
.decode((self, sess))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
|
fn load_proc_macro(&self, def_id: DefId, sess: &Session) -> SyntaxExtension {
|
||||||
let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) {
|
let (name, kind, helper_attrs) = match *self.raw_proc_macro(def_id.index) {
|
||||||
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
||||||
let helper_attrs =
|
let helper_attrs =
|
||||||
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
|
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
|
||||||
(
|
(
|
||||||
trait_name,
|
trait_name,
|
||||||
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { client })),
|
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
|
||||||
|
client,
|
||||||
|
krate: def_id.krate,
|
||||||
|
})),
|
||||||
helper_attrs,
|
helper_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ProcMacro::Attr { name, client } => {
|
ProcMacro::Attr { name, client } => (
|
||||||
(name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new())
|
name,
|
||||||
}
|
SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client, krate: def_id.krate })),
|
||||||
ProcMacro::Bang { name, client } => {
|
Vec::new(),
|
||||||
(name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new())
|
),
|
||||||
}
|
ProcMacro::Bang { name, client } => (
|
||||||
|
name,
|
||||||
|
SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client, krate: def_id.krate })),
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let attrs: Vec<_> = self.get_item_attrs(id, sess).collect();
|
let attrs: Vec<_> = self.get_item_attrs(def_id.index, sess).collect();
|
||||||
SyntaxExtension::new(
|
SyntaxExtension::new(
|
||||||
sess,
|
sess,
|
||||||
kind,
|
kind,
|
||||||
self.get_span(id, sess),
|
self.get_span(def_id.index, sess),
|
||||||
helper_attrs,
|
helper_attrs,
|
||||||
self.root.edition,
|
self.root.edition,
|
||||||
Symbol::intern(name),
|
Symbol::intern(name),
|
||||||
|
@ -1379,6 +1386,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_proc_macro_quoted_span(&self, index: usize, sess: &Session) -> Span {
|
||||||
|
self.root
|
||||||
|
.tables
|
||||||
|
.proc_macro_quoted_spans
|
||||||
|
.get(self, index)
|
||||||
|
.unwrap_or_else(|| panic!("Missing proc macro quoted span: {:?}", index))
|
||||||
|
.decode((self, sess))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> {
|
fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> {
|
||||||
if self.root.is_proc_macro_crate() {
|
if self.root.is_proc_macro_crate() {
|
||||||
// Proc macro crates do not have any *target* foreign modules.
|
// Proc macro crates do not have any *target* foreign modules.
|
||||||
|
|
|
@ -411,7 +411,7 @@ impl CStore {
|
||||||
|
|
||||||
let data = self.get_crate_data(id.krate);
|
let data = self.get_crate_data(id.krate);
|
||||||
if data.root.is_proc_macro_crate() {
|
if data.root.is_proc_macro_crate() {
|
||||||
return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess));
|
return LoadedMacro::ProcMacro(data.load_proc_macro(id, sess));
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = data.get_span(id.index, sess);
|
let span = data.get_span(id.index, sess);
|
||||||
|
@ -461,6 +461,15 @@ impl CStore {
|
||||||
pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
|
pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
|
||||||
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
|
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_proc_macro_quoted_span_untracked(
|
||||||
|
&self,
|
||||||
|
cnum: CrateNum,
|
||||||
|
id: usize,
|
||||||
|
sess: &Session,
|
||||||
|
) -> Span {
|
||||||
|
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrateStore for CStore {
|
impl CrateStore for CStore {
|
||||||
|
|
|
@ -1579,6 +1579,11 @@ impl EncodeContext<'a, 'tcx> {
|
||||||
let proc_macro_decls_static = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap().index;
|
let proc_macro_decls_static = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap().index;
|
||||||
let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied();
|
let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied();
|
||||||
let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index));
|
let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index));
|
||||||
|
let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
|
||||||
|
for (i, span) in spans.into_iter().enumerate() {
|
||||||
|
let span = self.lazy(span);
|
||||||
|
self.tables.proc_macro_quoted_spans.set(i, span);
|
||||||
|
}
|
||||||
|
|
||||||
record!(self.tables.def_kind[LOCAL_CRATE.as_def_id()] <- DefKind::Mod);
|
record!(self.tables.def_kind[LOCAL_CRATE.as_def_id()] <- DefKind::Mod);
|
||||||
record!(self.tables.span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
|
record!(self.tables.span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
|
||||||
|
|
|
@ -258,15 +258,15 @@ crate struct TraitImpls {
|
||||||
|
|
||||||
/// Define `LazyTables` and `TableBuilders` at the same time.
|
/// Define `LazyTables` and `TableBuilders` at the same time.
|
||||||
macro_rules! define_tables {
|
macro_rules! define_tables {
|
||||||
($($name:ident: Table<DefIndex, $T:ty>),+ $(,)?) => {
|
($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => {
|
||||||
#[derive(MetadataEncodable, MetadataDecodable)]
|
#[derive(MetadataEncodable, MetadataDecodable)]
|
||||||
crate struct LazyTables<'tcx> {
|
crate struct LazyTables<'tcx> {
|
||||||
$($name: Lazy!(Table<DefIndex, $T>)),+
|
$($name: Lazy!(Table<$IDX, $T>)),+
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct TableBuilders<'tcx> {
|
struct TableBuilders<'tcx> {
|
||||||
$($name: TableBuilder<DefIndex, $T>),+
|
$($name: TableBuilder<$IDX, $T>),+
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableBuilders<'tcx> {
|
impl TableBuilders<'tcx> {
|
||||||
|
@ -315,6 +315,7 @@ define_tables! {
|
||||||
// definitions from any given crate.
|
// definitions from any given crate.
|
||||||
def_keys: Table<DefIndex, Lazy<DefKey>>,
|
def_keys: Table<DefIndex, Lazy<DefKey>>,
|
||||||
def_path_hashes: Table<DefIndex, Lazy<DefPathHash>>,
|
def_path_hashes: Table<DefIndex, Lazy<DefPathHash>>,
|
||||||
|
proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
|
#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
|
||||||
|
|
|
@ -389,7 +389,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
|
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
|
||||||
ExpnKind::Macro(MacroKind::Bang, _) => {
|
ExpnKind::Macro { kind: MacroKind::Bang, name: _, proc_macro: _ } => {
|
||||||
// Dummy span for the `def_site` means it's an external macro.
|
// Dummy span for the `def_site` means it's an external macro.
|
||||||
expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
|
expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
if expn_data.is_root() {
|
if expn_data.is_root() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if let ExpnKind::Macro(..) = expn_data.kind {
|
if let ExpnKind::Macro { .. } = expn_data.kind {
|
||||||
body_span = expn_data.call_site;
|
body_span = expn_data.call_site;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -184,8 +184,11 @@ impl CoverageSpan {
|
||||||
self.current_macro_or_none
|
self.current_macro_or_none
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.get_or_insert_with(|| {
|
.get_or_insert_with(|| {
|
||||||
if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
|
if let ExpnKind::Macro {
|
||||||
self.expn_span.ctxt().outer_expn_data().kind
|
kind: MacroKind::Bang,
|
||||||
|
name: current_macro,
|
||||||
|
proc_macro: _,
|
||||||
|
} = self.expn_span.ctxt().outer_expn_data().kind
|
||||||
{
|
{
|
||||||
return Some(current_macro);
|
return Some(current_macro);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1770,9 +1770,11 @@ impl<'a> Resolver<'a> {
|
||||||
let expn_data = expn_id.expn_data();
|
let expn_data = expn_id.expn_data();
|
||||||
match expn_data.kind {
|
match expn_data.kind {
|
||||||
ExpnKind::Root
|
ExpnKind::Root
|
||||||
| ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
|
| ExpnKind::Macro {
|
||||||
Scope::DeriveHelpersCompat
|
kind: MacroKind::Bang | MacroKind::Derive,
|
||||||
}
|
name: _,
|
||||||
|
proc_macro: _,
|
||||||
|
} => Scope::DeriveHelpersCompat,
|
||||||
_ => Scope::DeriveHelpers(expn_data.parent),
|
_ => Scope::DeriveHelpers(expn_data.parent),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc_expand::compile_declarative_macro;
|
||||||
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
|
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
|
||||||
use rustc_feature::is_builtin_attr_name;
|
use rustc_feature::is_builtin_attr_name;
|
||||||
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
|
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
|
||||||
use rustc_hir::def_id;
|
use rustc_hir::def_id::{self, CrateNum};
|
||||||
use rustc_hir::PrimTy;
|
use rustc_hir::PrimTy;
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
@ -325,7 +325,11 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
||||||
let expn_data = expn_id.expn_data();
|
let expn_data = expn_id.expn_data();
|
||||||
match expn_data.kind {
|
match expn_data.kind {
|
||||||
ExpnKind::Root
|
ExpnKind::Root
|
||||||
| ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
|
| ExpnKind::Macro {
|
||||||
|
name: _,
|
||||||
|
kind: MacroKind::Bang | MacroKind::Derive,
|
||||||
|
proc_macro: _,
|
||||||
|
} => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => expn_id = expn_data.parent,
|
_ => expn_id = expn_data.parent,
|
||||||
|
@ -462,6 +466,10 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
||||||
.emit();
|
.emit();
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span {
|
||||||
|
self.crate_loader.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.session)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Resolver<'a> {
|
impl<'a> Resolver<'a> {
|
||||||
|
|
|
@ -786,7 +786,7 @@ impl<'tcx> SaveContext<'tcx> {
|
||||||
let callee = span.source_callee()?;
|
let callee = span.source_callee()?;
|
||||||
|
|
||||||
let mac_name = match callee.kind {
|
let mac_name = match callee.kind {
|
||||||
ExpnKind::Macro(kind, name) => match kind {
|
ExpnKind::Macro { kind, name, proc_macro: _ } => match kind {
|
||||||
MacroKind::Bang => name,
|
MacroKind::Bang => name,
|
||||||
|
|
||||||
// Ignore attribute macros, their spans are usually mangled
|
// Ignore attribute macros, their spans are usually mangled
|
||||||
|
|
|
@ -137,6 +137,9 @@ pub struct ParseSess {
|
||||||
pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
|
pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
|
||||||
/// Whether cfg(version) should treat the current release as incomplete
|
/// Whether cfg(version) should treat the current release as incomplete
|
||||||
pub assume_incomplete_release: bool,
|
pub assume_incomplete_release: bool,
|
||||||
|
/// Spans passed to `proc_macro::quote_span`. Each span has a numerical
|
||||||
|
/// identifier represented by its position in the vector.
|
||||||
|
pub proc_macro_quoted_spans: Lock<Vec<Span>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseSess {
|
impl ParseSess {
|
||||||
|
@ -164,6 +167,7 @@ impl ParseSess {
|
||||||
env_depinfo: Default::default(),
|
env_depinfo: Default::default(),
|
||||||
type_ascription_path_suggestions: Default::default(),
|
type_ascription_path_suggestions: Default::default(),
|
||||||
assume_incomplete_release: false,
|
assume_incomplete_release: false,
|
||||||
|
proc_macro_quoted_spans: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,4 +240,14 @@ impl ParseSess {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn save_proc_macro_span(&self, span: Span) -> usize {
|
||||||
|
let mut spans = self.proc_macro_quoted_spans.lock();
|
||||||
|
spans.push(span);
|
||||||
|
return spans.len() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proc_macro_quoted_spans(&self) -> Vec<Span> {
|
||||||
|
self.proc_macro_quoted_spans.lock().clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,10 @@ impl ExpnId {
|
||||||
let expn_data = self.expn_data();
|
let expn_data = self.expn_data();
|
||||||
// Stop going up the backtrace once include! is encountered
|
// Stop going up the backtrace once include! is encountered
|
||||||
if expn_data.is_root()
|
if expn_data.is_root()
|
||||||
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
|
|| matches!(
|
||||||
|
expn_data.kind,
|
||||||
|
ExpnKind::Macro { kind: MacroKind::Bang, name: sym::include, proc_macro: _ }
|
||||||
|
)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -839,7 +842,13 @@ pub enum ExpnKind {
|
||||||
/// No expansion, aka root expansion. Only `ExpnId::root()` has this kind.
|
/// No expansion, aka root expansion. Only `ExpnId::root()` has this kind.
|
||||||
Root,
|
Root,
|
||||||
/// Expansion produced by a macro.
|
/// Expansion produced by a macro.
|
||||||
Macro(MacroKind, Symbol),
|
Macro {
|
||||||
|
kind: MacroKind,
|
||||||
|
name: Symbol,
|
||||||
|
/// If `true`, this macro is a procedural macro. This
|
||||||
|
/// flag is only used for diagnostic purposes
|
||||||
|
proc_macro: bool,
|
||||||
|
},
|
||||||
/// Transform done by the compiler on the AST.
|
/// Transform done by the compiler on the AST.
|
||||||
AstPass(AstPass),
|
AstPass(AstPass),
|
||||||
/// Desugaring done by the compiler during HIR lowering.
|
/// Desugaring done by the compiler during HIR lowering.
|
||||||
|
@ -852,7 +861,7 @@ impl ExpnKind {
|
||||||
pub fn descr(&self) -> String {
|
pub fn descr(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
ExpnKind::Root => kw::PathRoot.to_string(),
|
ExpnKind::Root => kw::PathRoot.to_string(),
|
||||||
ExpnKind::Macro(macro_kind, name) => match macro_kind {
|
ExpnKind::Macro { kind, name, proc_macro: _ } => match kind {
|
||||||
MacroKind::Bang => format!("{}!", name),
|
MacroKind::Bang => format!("{}!", name),
|
||||||
MacroKind::Attr => format!("#[{}]", name),
|
MacroKind::Attr => format!("#[{}]", name),
|
||||||
MacroKind::Derive => format!("#[derive({})]", name),
|
MacroKind::Derive => format!("#[derive({})]", name),
|
||||||
|
|
|
@ -394,7 +394,10 @@ impl Span {
|
||||||
|
|
||||||
/// Returns `true` if `span` originates in a derive-macro's expansion.
|
/// Returns `true` if `span` originates in a derive-macro's expansion.
|
||||||
pub fn in_derive_expansion(self) -> bool {
|
pub fn in_derive_expansion(self) -> bool {
|
||||||
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
|
matches!(
|
||||||
|
self.ctxt().outer_expn_data().kind,
|
||||||
|
ExpnKind::Macro { kind: MacroKind::Derive, name: _, proc_macro: _ }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -162,6 +162,8 @@ macro_rules! with_api {
|
||||||
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||||
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
||||||
fn source_text($self: $S::Span) -> Option<String>;
|
fn source_text($self: $S::Span) -> Option<String>;
|
||||||
|
fn save_span($self: $S::Span) -> usize;
|
||||||
|
fn recover_proc_macro_span(id: usize) -> $S::Span;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -338,6 +340,7 @@ mark_noop! {
|
||||||
&'a [u8],
|
&'a [u8],
|
||||||
&'a str,
|
&'a str,
|
||||||
String,
|
String,
|
||||||
|
usize,
|
||||||
Delimiter,
|
Delimiter,
|
||||||
Level,
|
Level,
|
||||||
LineColumn,
|
LineColumn,
|
||||||
|
|
|
@ -265,7 +265,7 @@ pub mod token_stream {
|
||||||
/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
|
/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
|
||||||
/// To quote `$` itself, use `$$`.
|
/// To quote `$` itself, use `$$`.
|
||||||
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
||||||
#[allow_internal_unstable(proc_macro_def_site)]
|
#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals)]
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
pub macro quote($($t:tt)*) {
|
pub macro quote($($t:tt)*) {
|
||||||
/* compiler built-in */
|
/* compiler built-in */
|
||||||
|
@ -394,6 +394,20 @@ impl Span {
|
||||||
self.0.source_text()
|
self.0.source_text()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used by the implementation of `Span::quote`
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||||
|
pub fn save_span(&self) -> usize {
|
||||||
|
self.0.save_span()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the implementation of `Span::quote`
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||||
|
pub fn recover_proc_macro_span(id: usize) -> Span {
|
||||||
|
Span(bridge::client::Span::recover_proc_macro_span(id))
|
||||||
|
}
|
||||||
|
|
||||||
diagnostic_method!(error, Level::Error);
|
diagnostic_method!(error, Level::Error);
|
||||||
diagnostic_method!(warning, Level::Warning);
|
diagnostic_method!(warning, Level::Warning);
|
||||||
diagnostic_method!(note, Level::Note);
|
diagnostic_method!(note, Level::Note);
|
||||||
|
|
|
@ -65,6 +65,7 @@ pub fn quote(stream: TokenStream) -> TokenStream {
|
||||||
if stream.is_empty() {
|
if stream.is_empty() {
|
||||||
return quote!(crate::TokenStream::new());
|
return quote!(crate::TokenStream::new());
|
||||||
}
|
}
|
||||||
|
let proc_macro_crate = quote!(crate);
|
||||||
let mut after_dollar = false;
|
let mut after_dollar = false;
|
||||||
let tokens = stream
|
let tokens = stream
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -105,7 +106,7 @@ pub fn quote(stream: TokenStream) -> TokenStream {
|
||||||
))),
|
))),
|
||||||
TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new(
|
TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new(
|
||||||
(@ TokenTree::from(Literal::string(&tt.to_string()))),
|
(@ TokenTree::from(Literal::string(&tt.to_string()))),
|
||||||
(@ quote_span(tt.span())),
|
(@ quote_span(proc_macro_crate.clone(), tt.span())),
|
||||||
))),
|
))),
|
||||||
TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({
|
TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({
|
||||||
let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string())))
|
let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string())))
|
||||||
|
@ -115,7 +116,7 @@ pub fn quote(stream: TokenStream) -> TokenStream {
|
||||||
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
|
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
|
||||||
(iter.next(), iter.next())
|
(iter.next(), iter.next())
|
||||||
{
|
{
|
||||||
lit.set_span((@ quote_span(tt.span())));
|
lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span())));
|
||||||
lit
|
lit
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -135,6 +136,7 @@ pub fn quote(stream: TokenStream) -> TokenStream {
|
||||||
/// Quote a `Span` into a `TokenStream`.
|
/// Quote a `Span` into a `TokenStream`.
|
||||||
/// This is needed to implement a custom quoter.
|
/// This is needed to implement a custom quoter.
|
||||||
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
||||||
pub fn quote_span(_: Span) -> TokenStream {
|
pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream {
|
||||||
quote!(crate::Span::def_site())
|
let id = span.save_span();
|
||||||
|
quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id)))))
|
||||||
}
|
}
|
||||||
|
|
31
src/test/ui/proc-macro/auxiliary/custom-quote.rs
Normal file
31
src/test/ui/proc-macro/auxiliary/custom-quote.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// force-host
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
#![feature(proc_macro_quote)]
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use proc_macro::*;
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn custom_quote(input: TokenStream) -> TokenStream {
|
||||||
|
let mut tokens: Vec<_> = input.into_iter().collect();
|
||||||
|
assert_eq!(tokens.len(), 1, "Unexpected input: {:?}", tokens);
|
||||||
|
match tokens.pop() {
|
||||||
|
Some(TokenTree::Ident(ident)) => {
|
||||||
|
assert_eq!(ident.to_string(), "my_ident");
|
||||||
|
|
||||||
|
let proc_macro_crate = TokenStream::from_str("::proc_macro").unwrap();
|
||||||
|
let quoted_span = proc_macro::quote_span(proc_macro_crate, ident.span());
|
||||||
|
let prefix = TokenStream::from_str(r#"let mut ident = proc_macro::Ident::new("my_ident", proc_macro::Span::call_site());"#).unwrap();
|
||||||
|
let set_span_method = TokenStream::from_str("ident.set_span").unwrap();
|
||||||
|
let set_span_arg = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Parenthesis, quoted_span)));
|
||||||
|
let suffix = TokenStream::from_str(";proc_macro::TokenStream::from(proc_macro::TokenTree::Ident(ident))").unwrap();
|
||||||
|
let full_stream: TokenStream = std::array::IntoIter::new([prefix, set_span_method, set_span_arg, suffix]).collect();
|
||||||
|
full_stream
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
49
src/test/ui/proc-macro/auxiliary/span-from-proc-macro.rs
Normal file
49
src/test/ui/proc-macro/auxiliary/span-from-proc-macro.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// force-host
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![feature(proc_macro_quote)]
|
||||||
|
#![feature(proc_macro_internals)] // FIXME - this shouldn't be necessary
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
extern crate custom_quote;
|
||||||
|
|
||||||
|
use proc_macro::{quote, TokenStream};
|
||||||
|
|
||||||
|
macro_rules! expand_to_quote {
|
||||||
|
() => {
|
||||||
|
quote! {
|
||||||
|
let bang_error: bool = 25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn error_from_bang(_input: TokenStream) -> TokenStream {
|
||||||
|
expand_to_quote!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn other_error_from_bang(_input: TokenStream) -> TokenStream {
|
||||||
|
custom_quote::custom_quote! {
|
||||||
|
my_ident
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream {
|
||||||
|
quote! {
|
||||||
|
struct AttributeError {
|
||||||
|
field: MissingType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(ErrorFromDerive)]
|
||||||
|
pub fn error_from_derive(_input: TokenStream) -> TokenStream {
|
||||||
|
quote! {
|
||||||
|
enum DeriveError {
|
||||||
|
Variant(OtherMissingType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,10 +45,10 @@ fn main /* 0#0 */() { ; }
|
||||||
Expansions:
|
Expansions:
|
||||||
0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
|
0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
|
||||||
1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
||||||
2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
|
2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro { kind: Bang, name: "produce_it", proc_macro: false }
|
||||||
3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
||||||
4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
|
4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro { kind: Bang, name: "meta_macro::print_def_site", proc_macro: true }
|
||||||
5: parent: ExpnId(4), call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
|
5: parent: ExpnId(4), call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro { kind: Bang, name: "$crate::dummy", proc_macro: true }
|
||||||
|
|
||||||
SyntaxContexts:
|
SyntaxContexts:
|
||||||
#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
|
#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
|
||||||
|
|
|
@ -69,10 +69,10 @@ fn main /* 0#0 */() { }
|
||||||
Expansions:
|
Expansions:
|
||||||
0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
|
0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
|
||||||
1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
||||||
2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
|
2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro { kind: Bang, name: "outer", proc_macro: false }
|
||||||
3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
|
||||||
4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
|
4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro { kind: Bang, name: "inner", proc_macro: false }
|
||||||
5: parent: ExpnId(4), call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
|
5: parent: ExpnId(4), call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro { kind: Bang, name: "print_bang", proc_macro: true }
|
||||||
|
|
||||||
SyntaxContexts:
|
SyntaxContexts:
|
||||||
#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
|
#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
|
||||||
|
|
18
src/test/ui/proc-macro/quote-debug.rs
Normal file
18
src/test/ui/proc-macro/quote-debug.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// check-pass
|
||||||
|
// force-host
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// compile-flags: -Z unpretty=expanded
|
||||||
|
//
|
||||||
|
// This file is not actually used as a proc-macro - instead,
|
||||||
|
// it's just used to show the output of the `quote!` macro
|
||||||
|
|
||||||
|
#![feature(proc_macro_quote)]
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
proc_macro::quote! {
|
||||||
|
let hello = "world";
|
||||||
|
}
|
||||||
|
}
|
52
src/test/ui/proc-macro/quote-debug.stdout
Normal file
52
src/test/ui/proc-macro/quote-debug.stdout
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#![feature(prelude_import)]
|
||||||
|
#![no_std]
|
||||||
|
// check-pass
|
||||||
|
// force-host
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// compile-flags: -Z unpretty=expanded
|
||||||
|
//
|
||||||
|
// This file is not actually used as a proc-macro - instead,
|
||||||
|
// it's just used to show the output of the `quote!` macro
|
||||||
|
|
||||||
|
#![feature(proc_macro_quote)]
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
#[prelude_import]
|
||||||
|
use ::std::prelude::rust_2015::*;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
[crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let",
|
||||||
|
crate::Span::recover_proc_macro_span(0)))),
|
||||||
|
crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello",
|
||||||
|
crate::Span::recover_proc_macro_span(1)))),
|
||||||
|
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}',
|
||||||
|
crate::Spacing::Alone))),
|
||||||
|
crate::TokenStream::from(crate::TokenTree::Literal({
|
||||||
|
let mut iter =
|
||||||
|
"\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
|
||||||
|
if let (Some(crate::TokenTree::Literal(mut lit)),
|
||||||
|
None) =
|
||||||
|
(iter.next(),
|
||||||
|
iter.next())
|
||||||
|
{
|
||||||
|
lit.set_span(crate::Span::recover_proc_macro_span(2));
|
||||||
|
lit
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
::core::panicking::panic("internal error: entered unreachable code")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}',
|
||||||
|
crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>()
|
||||||
|
}
|
||||||
|
const _: () =
|
||||||
|
{
|
||||||
|
extern crate proc_macro;
|
||||||
|
#[rustc_proc_macro_decls]
|
||||||
|
#[allow(deprecated)]
|
||||||
|
static _DECLS: &[proc_macro::bridge::client::ProcMacro] = &[];
|
||||||
|
};
|
17
src/test/ui/proc-macro/span-from-proc-macro.rs
Normal file
17
src/test/ui/proc-macro/span-from-proc-macro.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// aux-build:custom-quote.rs
|
||||||
|
// aux-build:span-from-proc-macro.rs
|
||||||
|
// compile-flags: -Z macro-backtrace
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate span_from_proc_macro;
|
||||||
|
|
||||||
|
#[error_from_attribute] //~ ERROR cannot find type `MissingType`
|
||||||
|
struct ShouldBeRemoved;
|
||||||
|
|
||||||
|
#[derive(ErrorFromDerive)] //~ ERROR cannot find type `OtherMissingType`
|
||||||
|
struct Kept;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
error_from_bang!(); //~ ERROR mismatched types
|
||||||
|
other_error_from_bang!(); //~ ERROR cannot find value `my_ident`
|
||||||
|
}
|
62
src/test/ui/proc-macro/span-from-proc-macro.stderr
Normal file
62
src/test/ui/proc-macro/span-from-proc-macro.stderr
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
error[E0412]: cannot find type `MissingType` in this scope
|
||||||
|
--> $DIR/auxiliary/span-from-proc-macro.rs:37:20
|
||||||
|
|
|
||||||
|
LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream {
|
||||||
|
| ----------------------------------------------------------------------------------- in this expansion of procedural macro `#[error_from_attribute]`
|
||||||
|
...
|
||||||
|
LL | field: MissingType
|
||||||
|
| ^^^^^^^^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
::: $DIR/span-from-proc-macro.rs:8:1
|
||||||
|
|
|
||||||
|
LL | #[error_from_attribute]
|
||||||
|
| ----------------------- in this macro invocation
|
||||||
|
|
||||||
|
error[E0412]: cannot find type `OtherMissingType` in this scope
|
||||||
|
--> $DIR/auxiliary/span-from-proc-macro.rs:46:21
|
||||||
|
|
|
||||||
|
LL | pub fn error_from_derive(_input: TokenStream) -> TokenStream {
|
||||||
|
| ------------------------------------------------------------ in this expansion of procedural macro `#[derive(ErrorFromDerive)]`
|
||||||
|
...
|
||||||
|
LL | Variant(OtherMissingType)
|
||||||
|
| ^^^^^^^^^^^^^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
::: $DIR/span-from-proc-macro.rs:11:10
|
||||||
|
|
|
||||||
|
LL | #[derive(ErrorFromDerive)]
|
||||||
|
| --------------- in this macro invocation
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `my_ident` in this scope
|
||||||
|
--> $DIR/auxiliary/span-from-proc-macro.rs:29:9
|
||||||
|
|
|
||||||
|
LL | pub fn other_error_from_bang(_input: TokenStream) -> TokenStream {
|
||||||
|
| ---------------------------------------------------------------- in this expansion of procedural macro `other_error_from_bang!`
|
||||||
|
LL | custom_quote::custom_quote! {
|
||||||
|
LL | my_ident
|
||||||
|
| ^^^^^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
::: $DIR/span-from-proc-macro.rs:16:5
|
||||||
|
|
|
||||||
|
LL | other_error_from_bang!();
|
||||||
|
| ------------------------- in this macro invocation
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/auxiliary/span-from-proc-macro.rs:16:36
|
||||||
|
|
|
||||||
|
LL | let bang_error: bool = 25;
|
||||||
|
| ---- ^^ expected `bool`, found integer
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
...
|
||||||
|
LL | pub fn error_from_bang(_input: TokenStream) -> TokenStream {
|
||||||
|
| ---------------------------------------------------------- in this expansion of procedural macro `error_from_bang!`
|
||||||
|
|
|
||||||
|
::: $DIR/span-from-proc-macro.rs:15:5
|
||||||
|
|
|
||||||
|
LL | error_from_bang!();
|
||||||
|
| ------------------- in this macro invocation
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0308, E0412, E0425.
|
||||||
|
For more information about an error, try `rustc --explain E0308`.
|
|
@ -660,7 +660,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
if expr.span.from_expansion() {
|
if expr.span.from_expansion() {
|
||||||
let data = expr.span.ctxt().outer_expn_data();
|
let data = expr.span.ctxt().outer_expn_data();
|
||||||
matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _))
|
matches!(data.kind, ExpnKind::Macro { kind: MacroKind::Attr, name: _, proc_macro: _ })
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use super::UNIT_CMP;
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if expr.span.from_expansion() {
|
if expr.span.from_expansion() {
|
||||||
if let Some(callee) = expr.span.source_callee() {
|
if let Some(callee) = expr.span.source_callee() {
|
||||||
if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
|
if let ExpnKind::Macro { kind: MacroKind::Bang, name: symbol, proc_macro: _ } = callee.kind {
|
||||||
if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
|
if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
|
||||||
let op = cmp.node;
|
let op = cmp.node;
|
||||||
if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
|
if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
|
||||||
|
|
|
@ -947,7 +947,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
|
||||||
let data = span.ctxt().outer_expn_data();
|
let data = span.ctxt().outer_expn_data();
|
||||||
let new_span = data.call_site;
|
let new_span = data.call_site;
|
||||||
|
|
||||||
if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
|
if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind {
|
||||||
if mac_name.as_str() == name {
|
if mac_name.as_str() == name {
|
||||||
return Some(new_span);
|
return Some(new_span);
|
||||||
}
|
}
|
||||||
|
@ -975,7 +975,7 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
|
||||||
let data = span.ctxt().outer_expn_data();
|
let data = span.ctxt().outer_expn_data();
|
||||||
let new_span = data.call_site;
|
let new_span = data.call_site;
|
||||||
|
|
||||||
if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
|
if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind {
|
||||||
if mac_name.as_str() == name {
|
if mac_name.as_str() == name {
|
||||||
return Some(new_span);
|
return Some(new_span);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue