Skip to content

Commit 5fe695a

Browse files
committed
Auto merge of #53913 - petrochenkov:biattr4, r=<try>
resolve: Future proof resolutions for potentially built-in attributes Based on #53778 This is not full "pass all attributes through name resolution", but a more conservative solution. If built-in attribute is ambiguous with any other macro in scope, then an error is reported. TODO: Explain what complications arise with the full solution. cc #50911 (comment) Closes #53531
2 parents 591a17d + ebb7a7b commit 5fe695a

25 files changed

+1578
-247
lines changed

src/librustc_resolve/build_reduced_graph.rs

+24-11
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use syntax::ext::base::{MacroKind, SyntaxExtension};
3939
use syntax::ext::base::Determinacy::Undetermined;
4040
use syntax::ext::hygiene::Mark;
4141
use syntax::ext::tt::macro_rules;
42+
use syntax::feature_gate::is_builtin_attr;
4243
use syntax::parse::token::{self, Token};
4344
use syntax::std_inject::injected_crate_name;
4445
use syntax::symbol::keywords;
@@ -933,7 +934,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
933934

934935
pub struct BuildReducedGraphVisitor<'a, 'b: 'a, 'c: 'b> {
935936
pub resolver: &'a mut Resolver<'b, 'c>,
936-
pub legacy_scope: LegacyScope<'b>,
937+
pub current_legacy_scope: LegacyScope<'b>,
937938
pub expansion: Mark,
938939
}
939940

@@ -943,7 +944,8 @@ impl<'a, 'b, 'cl> BuildReducedGraphVisitor<'a, 'b, 'cl> {
943944
self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
944945
let invocation = self.resolver.invocations[&mark];
945946
invocation.module.set(self.resolver.current_module);
946-
invocation.legacy_scope.set(self.legacy_scope);
947+
invocation.parent_legacy_scope.set(self.current_legacy_scope);
948+
invocation.output_legacy_scope.set(self.current_legacy_scope);
947949
invocation
948950
}
949951
}
@@ -969,29 +971,30 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
969971
fn visit_item(&mut self, item: &'a Item) {
970972
let macro_use = match item.node {
971973
ItemKind::MacroDef(..) => {
972-
self.resolver.define_macro(item, self.expansion, &mut self.legacy_scope);
974+
self.resolver.define_macro(item, self.expansion, &mut self.current_legacy_scope);
973975
return
974976
}
975977
ItemKind::Mac(..) => {
976-
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
978+
self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(item.id));
977979
return
978980
}
979981
ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
980982
_ => false,
981983
};
982984

983-
let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
985+
let orig_current_module = self.resolver.current_module;
986+
let orig_current_legacy_scope = self.current_legacy_scope;
984987
self.resolver.build_reduced_graph_for_item(item, self.expansion);
985988
visit::walk_item(self, item);
986-
self.resolver.current_module = parent;
989+
self.resolver.current_module = orig_current_module;
987990
if !macro_use {
988-
self.legacy_scope = legacy_scope;
991+
self.current_legacy_scope = orig_current_legacy_scope;
989992
}
990993
}
991994

992995
fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
993996
if let ast::StmtKind::Mac(..) = stmt.node {
994-
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id));
997+
self.current_legacy_scope = LegacyScope::Invocation(self.visit_invoc(stmt.id));
995998
} else {
996999
visit::walk_stmt(self, stmt);
9971000
}
@@ -1008,11 +1011,12 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
10081011
}
10091012

10101013
fn visit_block(&mut self, block: &'a Block) {
1011-
let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
1014+
let orig_current_module = self.resolver.current_module;
1015+
let orig_current_legacy_scope = self.current_legacy_scope;
10121016
self.resolver.build_reduced_graph_for_block(block, self.expansion);
10131017
visit::walk_block(self, block);
1014-
self.resolver.current_module = parent;
1015-
self.legacy_scope = legacy_scope;
1018+
self.resolver.current_module = orig_current_module;
1019+
self.current_legacy_scope = orig_current_legacy_scope;
10161020
}
10171021

10181022
fn visit_trait_item(&mut self, item: &'a TraitItem) {
@@ -1057,4 +1061,13 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
10571061
}
10581062
}
10591063
}
1064+
1065+
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
1066+
if !attr.is_sugared_doc && is_builtin_attr(attr) {
1067+
self.resolver.current_module.builtin_attrs.borrow_mut().push((
1068+
attr.path.segments[0].ident, self.expansion, self.current_legacy_scope
1069+
));
1070+
}
1071+
visit::walk_attribute(self, attr);
1072+
}
10601073
}

src/librustc_resolve/lib.rs

+54-48
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ use std::mem::replace;
8181
use rustc_data_structures::sync::Lrc;
8282

8383
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
84-
use macros::{InvocationData, LegacyBinding};
84+
use macros::{InvocationData, LegacyBinding, LegacyScope};
8585

8686
// NB: This module needs to be declared first so diagnostics are
8787
// registered before they are used.
@@ -1010,8 +1010,9 @@ pub struct ModuleData<'a> {
10101010
normal_ancestor_id: DefId,
10111011

10121012
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
1013-
legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, MacroKind, Option<Def>)>>,
1013+
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>,
10141014
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
1015+
builtin_attrs: RefCell<Vec<(Ident, Mark, LegacyScope<'a>)>>,
10151016

10161017
// Macro invocations that can expand into items in this module.
10171018
unresolved_invocations: RefCell<FxHashSet<Mark>>,
@@ -1050,6 +1051,7 @@ impl<'a> ModuleData<'a> {
10501051
resolutions: RefCell::new(FxHashMap()),
10511052
legacy_macro_resolutions: RefCell::new(Vec::new()),
10521053
macro_resolutions: RefCell::new(Vec::new()),
1054+
builtin_attrs: RefCell::new(Vec::new()),
10531055
unresolved_invocations: RefCell::new(FxHashSet()),
10541056
no_implicit_prelude: false,
10551057
glob_importers: RefCell::new(Vec::new()),
@@ -1166,7 +1168,6 @@ struct UseError<'a> {
11661168
struct AmbiguityError<'a> {
11671169
span: Span,
11681170
name: Name,
1169-
lexical: bool,
11701171
b1: &'a NameBinding<'a>,
11711172
b2: &'a NameBinding<'a>,
11721173
}
@@ -1270,6 +1271,23 @@ impl<'a> NameBinding<'a> {
12701271
fn descr(&self) -> &'static str {
12711272
if self.is_extern_crate() { "extern crate" } else { self.def().kind_name() }
12721273
}
1274+
1275+
// Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding`
1276+
// at some expansion round `max(invoc, binding)` when they both emerged from macros.
1277+
// Then this function returns `true` if `self` may emerge from a macro *after* that
1278+
// in some later round and screw up our previously found resolution.
1279+
fn may_appear_after(&self, invoc_parent_expansion: Mark, binding: &NameBinding) -> bool {
1280+
// self > max(invoc, binding) => !(self <= invoc || self <= binding)
1281+
// Expansions are partially ordered, so "may appear after" is an inversion of
1282+
// "certainly appears before or simultaneously" and includes unordered cases.
1283+
let self_parent_expansion = self.expansion;
1284+
let other_parent_expansion = binding.expansion;
1285+
let certainly_before_other_or_simultaneously =
1286+
other_parent_expansion.is_descendant_of(self_parent_expansion);
1287+
let certainly_before_invoc_or_simultaneously =
1288+
invoc_parent_expansion.is_descendant_of(self_parent_expansion);
1289+
!(certainly_before_other_or_simultaneously || certainly_before_invoc_or_simultaneously)
1290+
}
12731291
}
12741292

12751293
/// Interns the names of the primitive types.
@@ -1403,8 +1421,6 @@ pub struct Resolver<'a, 'b: 'a> {
14031421
proc_mac_errors: Vec<macros::ProcMacError>,
14041422
/// crate-local macro expanded `macro_export` referred to by a module-relative path
14051423
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>,
1406-
/// macro-expanded `macro_rules` shadowing existing macros
1407-
disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
14081424

14091425
arenas: &'a ResolverArenas<'a>,
14101426
dummy_binding: &'a NameBinding<'a>,
@@ -1715,7 +1731,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
17151731
ambiguity_errors: Vec::new(),
17161732
use_injections: Vec::new(),
17171733
proc_mac_errors: Vec::new(),
1718-
disallowed_shadowing: Vec::new(),
17191734
macro_expanded_macro_export_errors: BTreeSet::new(),
17201735

17211736
arenas,
@@ -1814,7 +1829,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18141829
NameBindingKind::Import { .. } => false,
18151830
NameBindingKind::Ambiguity { b1, b2 } => {
18161831
self.ambiguity_errors.push(AmbiguityError {
1817-
span, name: ident.name, lexical: false, b1, b2,
1832+
span, name: ident.name, b1, b2,
18181833
});
18191834
true
18201835
}
@@ -3468,6 +3483,20 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
34683483
record_used: bool,
34693484
path_span: Span,
34703485
crate_lint: CrateLint,
3486+
) -> PathResult<'a> {
3487+
self.resolve_path_with_parent_expansion(base_module, path, opt_ns, Mark::root(),
3488+
record_used, path_span, crate_lint)
3489+
}
3490+
3491+
fn resolve_path_with_parent_expansion(
3492+
&mut self,
3493+
base_module: Option<ModuleOrUniformRoot<'a>>,
3494+
path: &[Ident],
3495+
opt_ns: Option<Namespace>, // `None` indicates a module path
3496+
parent_expansion: Mark,
3497+
record_used: bool,
3498+
path_span: Span,
3499+
crate_lint: CrateLint,
34713500
) -> PathResult<'a> {
34723501
let mut module = base_module;
34733502
let mut allow_super = true;
@@ -3557,8 +3586,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
35573586
self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
35583587
} else if opt_ns == Some(MacroNS) {
35593588
assert!(ns == TypeNS);
3560-
self.resolve_lexical_macro_path_segment(ident, ns, record_used, record_used,
3561-
false, path_span).map(|(b, _)| b)
3589+
self.resolve_lexical_macro_path_segment(ident, ns, parent_expansion, record_used,
3590+
record_used, false, path_span)
3591+
.map(|(binding, _)| binding)
35623592
} else {
35633593
let record_used_id =
35643594
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
@@ -4499,35 +4529,32 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
44994529
vis.is_accessible_from(module.normal_ancestor_id, self)
45004530
}
45014531

4502-
fn report_ambiguity_error(
4503-
&self, name: Name, span: Span, _lexical: bool,
4504-
def1: Def, is_import1: bool, is_glob1: bool, from_expansion1: bool, span1: Span,
4505-
def2: Def, is_import2: bool, _is_glob2: bool, _from_expansion2: bool, span2: Span,
4506-
) {
4532+
fn report_ambiguity_error(&self, name: Name, span: Span, b1: &NameBinding, b2: &NameBinding) {
45074533
let participle = |is_import: bool| if is_import { "imported" } else { "defined" };
4508-
let msg1 = format!("`{}` could refer to the name {} here", name, participle(is_import1));
4534+
let msg1 =
4535+
format!("`{}` could refer to the name {} here", name, participle(b1.is_import()));
45094536
let msg2 =
4510-
format!("`{}` could also refer to the name {} here", name, participle(is_import2));
4511-
let note = if from_expansion1 {
4512-
Some(if let Def::Macro(..) = def1 {
4537+
format!("`{}` could also refer to the name {} here", name, participle(b2.is_import()));
4538+
let note = if b1.expansion != Mark::root() {
4539+
Some(if let Def::Macro(..) = b1.def() {
45134540
format!("macro-expanded {} do not shadow",
4514-
if is_import1 { "macro imports" } else { "macros" })
4541+
if b1.is_import() { "macro imports" } else { "macros" })
45154542
} else {
45164543
format!("macro-expanded {} do not shadow when used in a macro invocation path",
4517-
if is_import1 { "imports" } else { "items" })
4544+
if b1.is_import() { "imports" } else { "items" })
45184545
})
4519-
} else if is_glob1 {
4546+
} else if b1.is_glob_import() {
45204547
Some(format!("consider adding an explicit import of `{}` to disambiguate", name))
45214548
} else {
45224549
None
45234550
};
45244551

45254552
let mut err = struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
4526-
err.span_note(span1, &msg1);
4527-
match def2 {
4528-
Def::Macro(..) if span2.is_dummy() =>
4553+
err.span_note(b1.span, &msg1);
4554+
match b2.def() {
4555+
Def::Macro(..) if b2.span.is_dummy() =>
45294556
err.note(&format!("`{}` is also a builtin macro", name)),
4530-
_ => err.span_note(span2, &msg2),
4557+
_ => err.span_note(b2.span, &msg2),
45314558
};
45324559
if let Some(note) = note {
45334560
err.note(&note);
@@ -4536,7 +4563,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45364563
}
45374564

45384565
fn report_errors(&mut self, krate: &Crate) {
4539-
self.report_shadowing_errors();
45404566
self.report_with_use_injections(krate);
45414567
self.report_proc_macro_import(krate);
45424568
let mut reported_spans = FxHashSet();
@@ -4552,15 +4578,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45524578
);
45534579
}
45544580

4555-
for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
4581+
for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors {
45564582
if reported_spans.insert(span) {
4557-
self.report_ambiguity_error(
4558-
name, span, lexical,
4559-
b1.def(), b1.is_import(), b1.is_glob_import(),
4560-
b1.expansion != Mark::root(), b1.span,
4561-
b2.def(), b2.is_import(), b2.is_glob_import(),
4562-
b2.expansion != Mark::root(), b2.span,
4563-
);
4583+
self.report_ambiguity_error(name, span, b1, b2);
45644584
}
45654585
}
45664586

@@ -4580,20 +4600,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
45804600
}
45814601
}
45824602

4583-
fn report_shadowing_errors(&mut self) {
4584-
let mut reported_errors = FxHashSet();
4585-
for binding in replace(&mut self.disallowed_shadowing, Vec::new()) {
4586-
if self.resolve_legacy_scope(&binding.parent, binding.ident, false).is_some() &&
4587-
reported_errors.insert((binding.ident, binding.span)) {
4588-
let msg = format!("`{}` is already in scope", binding.ident);
4589-
self.session.struct_span_err(binding.span, &msg)
4590-
.note("macro-expanded `macro_rules!`s may not shadow \
4591-
existing macros (see RFC 1560)")
4592-
.emit();
4593-
}
4594-
}
4595-
}
4596-
45974603
fn report_conflict<'b>(&mut self,
45984604
parent: Module,
45994605
ident: Ident,

0 commit comments

Comments
 (0)