Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Clippy handling of ExpnKind::Desugaring #73468

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions src/librustc_middle/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
use rustc_session::lint::{builtin, Level, Lint, LintId};
use rustc_session::{DiagnosticMessageId, Session};
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
use rustc_span::hygiene::{ClosestAstOrMacro, MacroKind};
use rustc_span::source_map::{ExpnKind, MultiSpan};
use rustc_span::{Span, Symbol};

/// How a lint level was set.
Expand Down Expand Up @@ -337,16 +337,19 @@ pub fn struct_lint_level<'s, 'd>(
/// This is used to test whether a lint should not even begin to figure out whether it should
/// be reported on the current node.
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
let expn_data = span.ctxt().outer_expn_data();
match expn_data.kind {
ExpnKind::Root
| ExpnKind::Desugaring(DesugaringKind::ForLoop(_))
| ExpnKind::Desugaring(DesugaringKind::Operator) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// 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)
match span.ctxt().outer_expn().closest_ast_or_macro() {
ClosestAstOrMacro::Expn(expn_id) => {
let data = expn_id.expn_data();
match data.kind {
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
data.def_site.is_dummy() || sess.source_map().is_imported(data.def_site)
}
ExpnKind::Macro(_, _) => true, // definitely a plugin
ExpnKind::AstPass(_) => true, // well, it's "External"
_ => unreachable!("unexpected ExpnData {:?}", data),
}
}
ExpnKind::Macro(..) => true, // definitely a plugin
ClosestAstOrMacro::None => false,
}
}
60 changes: 59 additions & 1 deletion src/librustc_span/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,19 @@ impl ExpnId {
HygieneData::with(|data| data.expn_data(self).clone())
}

#[inline]
pub fn closest_ast_or_macro(self) -> ClosestAstOrMacro {
Aaron1011 marked this conversation as resolved.
Show resolved Hide resolved
HygieneData::with(|data| data.closest_ast_or_macro(self))
}

#[inline]
pub fn set_expn_data(self, expn_data: ExpnData) {
HygieneData::with(|data| {
let closest = data.determine_closest_ast_or_macro(self, &expn_data);
let old_closest = &mut data.closest_ast_or_macro[self.0 as usize];
assert!(old_closest.is_none(), "closest ast/macro data reset for an expansion ID");
*old_closest = Some(closest);

let old_expn_data = &mut data.expn_data[self.0 as usize];
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
*old_expn_data = Some(expn_data);
Expand Down Expand Up @@ -149,6 +159,10 @@ crate struct HygieneData {
/// between creation of an expansion ID and obtaining its data (e.g. macros are collected
/// first and then resolved later), so we use an `Option` here.
expn_data: Vec<Option<ExpnData>>,
/// Stores the computed `ClosestAstOrMacro` for each `ExpnId`. This is updated
/// at the same time as `expn_data`, and its contents it determined entirely
/// by the `ExpnData` - this field is just a cache.
closest_ast_or_macro: Vec<Option<ClosestAstOrMacro>>,
syntax_context_data: Vec<SyntaxContextData>,
syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
}
Expand All @@ -162,6 +176,7 @@ impl HygieneData {
edition,
Some(DefId::local(CRATE_DEF_INDEX)),
))],
closest_ast_or_macro: vec![Some(ClosestAstOrMacro::None)],
syntax_context_data: vec![SyntaxContextData {
outer_expn: ExpnId::root(),
outer_transparency: Transparency::Opaque,
Expand All @@ -178,9 +193,36 @@ impl HygieneData {
GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
}

fn determine_closest_ast_or_macro(
&self,
id: ExpnId,
expn_data: &ExpnData,
) -> ClosestAstOrMacro {
match expn_data.kind {
ExpnKind::Macro(_, _) | ExpnKind::AstPass(_) => ClosestAstOrMacro::Expn(id),
ExpnKind::Desugaring(_) | ExpnKind::Root => {
// Avoid using `HygieneData` when construction root
// `ExpnData`
if expn_data.call_site.ctxt() == SyntaxContext::root() {
ClosestAstOrMacro::None
} else {
self.closest_ast_or_macro(self.outer_expn(expn_data.call_site.ctxt()))
}
}
}
}

fn closest_ast_or_macro(&self, expn_id: ExpnId) -> ClosestAstOrMacro {
self.closest_ast_or_macro[expn_id.0 as usize].as_ref().copied().unwrap()
}

fn fresh_expn(&mut self, expn_data: Option<ExpnData>) -> ExpnId {
let expn_id = ExpnId(self.expn_data.len() as u32);
self.closest_ast_or_macro.push(
expn_data.as_ref().map(|data| self.determine_closest_ast_or_macro(expn_id, data)),
);
self.expn_data.push(expn_data);
ExpnId(self.expn_data.len() as u32 - 1)
expn_id
}

fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
Expand Down Expand Up @@ -684,6 +726,22 @@ pub struct ExpnData {
pub macro_def_id: Option<DefId>,
}

/// The closest `ExpnKind::AstPass` or `ExpnKind::Macro` to an `ExpnData`.
/// 'Closest' is determined by starting at the current `ExpnData`,
/// and walking up the `call_site` tree. If an `ExpnData` with
/// `Expn::AstPass` or `ExpnKind::Macro` is found, it is represented
/// by `ClosestAstOrMacro::Expn(id)`, where `id` is the `EpxId` of
/// the found `ExpnData`.
///
/// A `ClosestAstOrMacro` implies that no `ExpnKind::AstPass` or `ExpnKind::Macro`
/// are found anywhere in the `call_site` tree - that is, there no macro
/// expansions or ast pass expansions.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ClosestAstOrMacro {
None,
Expn(ExpnId),
}

impl ExpnData {
/// Constructs expansion data with default properties.
pub fn default(
Expand Down