Skip to content

Commit 60f733e

Browse files
committed
WIP
1 parent 67d0e5b commit 60f733e

14 files changed

+240
-75
lines changed

compiler/rustc_lint/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ lint_opaque_hidden_inferred_bound_sugg = add this bound
603603
lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
604604
.suggestion = use pat_param to preserve semantics
605605
606+
lint_out_of_scope_macro_calls = cannot find macro `{$path}` in this scope
607+
606608
lint_overflowing_bin_hex = literal out of range for `{$ty}`
607609
.negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
608610
.negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}`

compiler/rustc_lint/src/context/diagnostics.rs

+3
Original file line numberDiff line numberDiff line change
@@ -424,5 +424,8 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
424424
lints::InnerAttributeUnstable::CustomInnerAttribute
425425
}
426426
.decorate_lint(diag),
427+
BuiltinLintDiag::OutOfScopeMacroCalls { path } => {
428+
lints::OutOfScopeMacroCalls { path }.decorate_lint(diag)
429+
}
427430
}
428431
}

compiler/rustc_lint/src/lints.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2888,3 +2888,9 @@ pub struct RedundantImportVisibility {
28882888
pub import_vis: String,
28892889
pub max_vis: String,
28902890
}
2891+
2892+
#[derive(LintDiagnostic)]
2893+
#[diag(lint_out_of_scope_macro_calls)]
2894+
pub struct OutOfScopeMacroCalls {
2895+
pub path: String,
2896+
}

compiler/rustc_lint_defs/src/builtin.rs

+37
Original file line numberDiff line numberDiff line change
@@ -4902,3 +4902,40 @@ declare_lint! {
49024902
reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>",
49034903
};
49044904
}
4905+
4906+
declare_lint! {
4907+
/// The `missing_unsafe_on_extern` lint detects missing unsafe keyword on extern declarations.
4908+
///
4909+
/// ### Example
4910+
///
4911+
/// ```rust
4912+
/// #![feature(unsafe_extern_blocks)]
4913+
/// #![warn(missing_unsafe_on_extern)]
4914+
/// #![allow(dead_code)]
4915+
///
4916+
/// extern "C" {
4917+
/// fn foo(_: i32);
4918+
/// }
4919+
///
4920+
/// fn main() {}
4921+
/// ```
4922+
///
4923+
/// {{produces}}
4924+
///
4925+
/// ### Explanation
4926+
///
4927+
/// Declaring extern items, even without ever using them, can cause Undefined Behavior. We
4928+
/// should consider all sources of Undefined Behavior to be unsafe.
4929+
///
4930+
/// This is a [future-incompatible] lint to transition this to a
4931+
/// hard error in the future.
4932+
///
4933+
/// [future-incompatible]: ../index.md#future-incompatible-lints
4934+
pub OUT_OF_SCOPE_MACRO_CALLS,
4935+
Deny,
4936+
"detects out of scope calls to `macro_rules` in key-value attributes",
4937+
@future_incompatible = FutureIncompatibleInfo {
4938+
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
4939+
reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>",
4940+
};
4941+
}

compiler/rustc_lint_defs/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,9 @@ pub enum BuiltinLintDiag {
742742
InnerAttributeUnstable {
743743
is_macro: bool,
744744
},
745+
OutOfScopeMacroCalls {
746+
path: String,
747+
},
745748
}
746749

747750
/// Lints that are buffered up early on in the `Session` before the

compiler/rustc_resolve/src/build_reduced_graph.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, Modul
1414
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError};
1515
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError};
1616

17-
use rustc_ast::visit::{self, AssocCtxt, Visitor};
17+
use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
1818
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
1919
use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
2020
use rustc_attr as attr;
@@ -1312,7 +1312,17 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
13121312
_ => {
13131313
let orig_macro_rules_scope = self.parent_scope.macro_rules;
13141314
self.build_reduced_graph_for_item(item);
1315-
visit::walk_item(self, item);
1315+
match item.kind {
1316+
ItemKind::Mod(..) => {
1317+
// Visit attributes after items for backward compatibility.
1318+
// This way they can use `macro_rules` defined later.
1319+
self.visit_vis(&item.vis);
1320+
self.visit_ident(item.ident);
1321+
item.kind.walk(item, AssocCtxt::Trait, self);
1322+
visit::walk_list!(self, visit_attribute, &item.attrs);
1323+
}
1324+
_ => visit::walk_item(self, item),
1325+
}
13161326
match item.kind {
13171327
ItemKind::Mod(..) if self.contains_macro_use(&item.attrs) => {
13181328
self.parent_scope.macro_rules
@@ -1502,7 +1512,10 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
15021512
if krate.is_placeholder {
15031513
self.visit_invoc_in_module(krate.id);
15041514
} else {
1505-
visit::walk_crate(self, krate);
1515+
// Visit attributes after items for backward compatibility.
1516+
// This way they can use `macro_rules` defined later.
1517+
visit::walk_list!(self, visit_item, &krate.items);
1518+
visit::walk_list!(self, visit_attribute, &krate.attrs);
15061519
self.contains_macro_use(&krate.attrs);
15071520
}
15081521
}

compiler/rustc_resolve/src/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
10461046
parent_scope,
10471047
false,
10481048
false,
1049+
None,
10491050
) {
10501051
suggestions.extend(
10511052
ext.helper_attrs

compiler/rustc_resolve/src/ident.rs

+1
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
457457
parent_scope,
458458
true,
459459
force,
460+
None,
460461
) {
461462
Ok((Some(ext), _)) => {
462463
if ext.helper_attrs.contains(&ident.name) {

compiler/rustc_resolve/src/late.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4144,7 +4144,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
41444144
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
41454145
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
41464146
if let Ok((_, res)) =
4147-
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false)
4147+
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
41484148
{
41494149
return Ok(Some(PartialRes::new(res)));
41504150
}

compiler/rustc_resolve/src/macros.rs

+63-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
55
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
66
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
77
use crate::Namespace::*;
8-
use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
8+
use crate::{BuiltinMacroState, Determinacy, MacroData, NameBindingKind, Used};
99
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
1010
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
1111
use rustc_ast::expand::StrippedCfgItem;
@@ -18,15 +18,18 @@ use rustc_errors::{Applicability, StashKey};
1818
use rustc_expand::base::{Annotatable, DeriveResolution, Indeterminate, ResolverExpand};
1919
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
2020
use rustc_expand::compile_declarative_macro;
21-
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
21+
use rustc_expand::expand::{
22+
AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion,
23+
};
2224
use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind};
2325
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
2426
use rustc_middle::middle::stability;
2527
use rustc_middle::ty::RegisteredTools;
2628
use rustc_middle::ty::{TyCtxt, Visibility};
27-
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
28-
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
29-
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
29+
use rustc_session::lint::builtin::{
30+
LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, SOFT_UNSTABLE,
31+
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACROS, UNUSED_MACRO_RULES,
32+
};
3033
use rustc_session::lint::BuiltinLintDiag;
3134
use rustc_session::parse::feature_err;
3235
use rustc_span::edit_distance::edit_distance;
@@ -277,6 +280,15 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
277280
let parent_scope = &ParentScope { derives, ..parent_scope };
278281
let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion();
279282
let node_id = invoc.expansion_data.lint_node_id;
283+
let invoc_in_mod_inert_attr = self
284+
.invocation_parents
285+
.get(&invoc_id)
286+
.or_else(|| self.invocation_parents.get(&eager_expansion_root))
287+
.map(|&(mod_def_id, _)| mod_def_id)
288+
.filter(|&mod_def_id| {
289+
invoc.fragment_kind == AstFragmentKind::Expr
290+
&& self.tcx.def_kind(mod_def_id) == DefKind::Mod
291+
});
280292
let (ext, res) = self.smart_resolve_macro_path(
281293
path,
282294
kind,
@@ -286,6 +298,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
286298
node_id,
287299
force,
288300
soft_custom_inner_attributes_gate(path, invoc),
301+
invoc_in_mod_inert_attr,
289302
)?;
290303

291304
let span = invoc.span();
@@ -366,6 +379,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
366379
&parent_scope,
367380
true,
368381
force,
382+
None,
369383
) {
370384
Ok((Some(ext), _)) => {
371385
if !ext.helper_attrs.is_empty() {
@@ -468,9 +482,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
468482
node_id: NodeId,
469483
force: bool,
470484
soft_custom_inner_attributes_gate: bool,
485+
invoc_in_mod_inert_attr: Option<LocalDefId>,
471486
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
472-
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
473-
{
487+
let (ext, res) = match self.resolve_macro_path(
488+
path,
489+
Some(kind),
490+
parent_scope,
491+
true,
492+
force,
493+
invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
494+
) {
474495
Ok((Some(ext), res)) => (ext, res),
475496
Ok((None, res)) => (self.dummy_ext(kind), res),
476497
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
@@ -600,14 +621,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
600621

601622
pub(crate) fn resolve_macro_path(
602623
&mut self,
603-
path: &ast::Path,
624+
ast_path: &ast::Path,
604625
kind: Option<MacroKind>,
605626
parent_scope: &ParentScope<'a>,
606627
trace: bool,
607628
force: bool,
629+
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
608630
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
609-
let path_span = path.span;
610-
let mut path = Segment::from_path(path);
631+
let path_span = ast_path.span;
632+
let mut path = Segment::from_path(ast_path);
611633

612634
// Possibly apply the macro helper hack
613635
if kind == Some(MacroKind::Bang)
@@ -667,6 +689,37 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
667689

668690
let res = binding.map(|binding| binding.res());
669691
self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span);
692+
if let Ok(binding) = binding
693+
&& matches!(binding.kind, NameBindingKind::Res(..))
694+
&& let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr
695+
&& let Ok(Res::Def(DefKind::Macro(MacroKind::Bang), def_id)) = res
696+
&& self.tcx.parent(def_id) == mod_def_id.to_def_id()
697+
{
698+
let tralala = self.early_resolve_ident_in_lexical_scope(
699+
path[0].ident,
700+
scope_set,
701+
&ParentScope {
702+
macro_rules: self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty),
703+
..*parent_scope
704+
},
705+
None,
706+
false,
707+
None,
708+
);
709+
710+
if tralala.ok().and_then(|binding| binding.res().opt_def_id()) == Some(def_id) {
711+
// Nothing
712+
} else {
713+
self.tcx.sess.psess.buffer_lint(
714+
OUT_OF_SCOPE_MACRO_CALLS,
715+
path_span,
716+
node_id,
717+
BuiltinLintDiag::OutOfScopeMacroCalls {
718+
path: pprust::path_to_string(ast_path),
719+
},
720+
);
721+
}
722+
}
670723
res
671724
};
672725

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ check-pass
2+
//@ edition:2018
3+
4+
#![doc = in_root!()]
5+
6+
macro_rules! in_root { () => { "" } }
7+
use in_root;
8+
9+
mod macros_stay {
10+
#![doc = in_mod!()]
11+
12+
macro_rules! in_mod { () => { "" } }
13+
use in_mod;
14+
}
15+
16+
fn main() {}

tests/ui/attributes/key-value-expansion-scope.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope
2+
//~| WARN this was previously accepted by the compiler
23
#![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope
3-
#![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope
4+
#![doc = in_mod_escape!()] //FIXME ERROR cannot find macro `in_mod_escape` in this scope
45
#![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope
56

67
#[doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope
@@ -16,8 +17,11 @@ fn before() {
1617

1718
macro_rules! in_root { () => { "" } }
1819

20+
#[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope
21+
//~| WARN this was previously accepted by the compiler
1922
mod macros_stay {
2023
#![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope
24+
//~| WARN this was previously accepted by the compiler
2125

2226
macro_rules! in_mod { () => { "" } }
2327

@@ -28,8 +32,11 @@ mod macros_stay {
2832
}
2933

3034
#[macro_use]
35+
#[doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope
36+
//~| WARN this was previously accepted by the compiler
3137
mod macros_escape {
3238
#![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope
39+
//~| WARN this was previously accepted by the compiler
3340

3441
macro_rules! in_mod_escape { () => { "" } }
3542

@@ -39,8 +46,9 @@ mod macros_escape {
3946
}
4047
}
4148

49+
#[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope
4250
fn block() {
43-
#![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope
51+
#![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope
4452

4553
macro_rules! in_block { () => { "" } }
4654

0 commit comments

Comments
 (0)