Skip to content

Commit 820653e

Browse files
committed
resolve: Check resolution consistency for import paths and multi-segment macro paths
1 parent 40e2177 commit 820653e

20 files changed

+371
-202
lines changed

src/librustc/hir/def.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ impl Def {
330330
match *self {
331331
Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::AssociatedExistential(..) |
332332
Def::Enum(..) | Def::Existential(..) | Def::Err => "an",
333+
Def::Macro(.., macro_kind) => macro_kind.article(),
333334
_ => "a",
334335
}
335336
}

src/librustc/hir/def_id.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ pub struct DefId {
225225

226226
impl fmt::Debug for DefId {
227227
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228-
write!(f, "DefId({:?}/{}:{}",
229-
self.krate.index(),
228+
write!(f, "DefId({}/{}:{}",
229+
self.krate,
230230
self.index.address_space().index(),
231231
self.index.as_array_index())?;
232232

src/librustc_resolve/lib.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,18 @@ enum ModuleOrUniformRoot<'a> {
988988
UniformRoot(UniformRootKind),
989989
}
990990

991+
impl<'a> PartialEq for ModuleOrUniformRoot<'a> {
992+
fn eq(&self, other: &Self) -> bool {
993+
match (*self, *other) {
994+
(ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) =>
995+
ptr::eq(lhs, rhs),
996+
(ModuleOrUniformRoot::UniformRoot(lhs), ModuleOrUniformRoot::UniformRoot(rhs)) =>
997+
lhs == rhs,
998+
_ => false,
999+
}
1000+
}
1001+
}
1002+
9911003
#[derive(Clone, Debug)]
9921004
enum PathResult<'a> {
9931005
Module(ModuleOrUniformRoot<'a>),
@@ -1029,9 +1041,10 @@ pub struct ModuleData<'a> {
10291041
normal_ancestor_id: DefId,
10301042

10311043
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
1032-
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
1033-
Option<&'a NameBinding<'a>>)>>,
1034-
macro_resolutions: RefCell<Vec<(Vec<Ident>, ParentScope<'a>, Span)>>,
1044+
single_segment_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
1045+
Option<&'a NameBinding<'a>>)>>,
1046+
multi_segment_macro_resolutions: RefCell<Vec<(Vec<Ident>, Span, MacroKind, ParentScope<'a>,
1047+
Option<Def>)>>,
10351048
builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
10361049

10371050
// Macro invocations that can expand into items in this module.
@@ -1069,8 +1082,8 @@ impl<'a> ModuleData<'a> {
10691082
kind,
10701083
normal_ancestor_id,
10711084
resolutions: Default::default(),
1072-
legacy_macro_resolutions: RefCell::new(Vec::new()),
1073-
macro_resolutions: RefCell::new(Vec::new()),
1085+
single_segment_macro_resolutions: RefCell::new(Vec::new()),
1086+
multi_segment_macro_resolutions: RefCell::new(Vec::new()),
10741087
builtin_attrs: RefCell::new(Vec::new()),
10751088
unresolved_invocations: Default::default(),
10761089
no_implicit_prelude: false,
@@ -1466,6 +1479,9 @@ pub struct Resolver<'a, 'b: 'a> {
14661479
/// The current self item if inside an ADT (used for better errors).
14671480
current_self_item: Option<NodeId>,
14681481

1482+
/// FIXME: Refactor things so that this is passed through arguments and not resolver.
1483+
last_import_segment: bool,
1484+
14691485
/// The idents for the primitive types.
14701486
primitive_type_table: PrimitiveTypeTable,
14711487

@@ -1793,6 +1809,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
17931809
current_trait_ref: None,
17941810
current_self_type: None,
17951811
current_self_item: None,
1812+
last_import_segment: false,
17961813

17971814
primitive_type_table: PrimitiveTypeTable::new(),
17981815

@@ -1894,27 +1911,23 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18941911
self.arenas.alloc_module(module)
18951912
}
18961913

1897-
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>)
1898-
-> bool /* true if an error was reported */ {
1914+
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>) {
18991915
match binding.kind {
1900-
NameBindingKind::Import { directive, binding, ref used }
1901-
if !used.get() => {
1916+
NameBindingKind::Import { directive, binding, ref used } if !used.get() => {
19021917
used.set(true);
19031918
directive.used.set(true);
19041919
self.used_imports.insert((directive.id, ns));
19051920
self.add_to_glob_map(directive.id, ident);
1906-
self.record_use(ident, ns, binding)
1921+
self.record_use(ident, ns, binding);
19071922
}
1908-
NameBindingKind::Import { .. } => false,
19091923
NameBindingKind::Ambiguity { kind, b1, b2 } => {
19101924
self.ambiguity_errors.push(AmbiguityError {
19111925
kind, ident, b1, b2,
19121926
misc1: AmbiguityErrorMisc::None,
19131927
misc2: AmbiguityErrorMisc::None,
19141928
});
1915-
true
19161929
}
1917-
_ => false
1930+
_ => {}
19181931
}
19191932
}
19201933

@@ -4735,7 +4748,6 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
47354748

47364749
fn report_errors(&mut self, krate: &Crate) {
47374750
self.report_with_use_injections(krate);
4738-
let mut reported_spans = FxHashSet::default();
47394751

47404752
for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
47414753
let msg = "macro-expanded `macro_export` macros from the current crate \
@@ -4749,11 +4761,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
47494761
}
47504762

47514763
for ambiguity_error in &self.ambiguity_errors {
4752-
if reported_spans.insert(ambiguity_error.ident.span) {
4753-
self.report_ambiguity_error(ambiguity_error);
4754-
}
4764+
self.report_ambiguity_error(ambiguity_error);
47554765
}
47564766

4767+
let mut reported_spans = FxHashSet::default();
47574768
for &PrivacyError(dedup_span, ident, binding) in &self.privacy_errors {
47584769
if reported_spans.insert(dedup_span) {
47594770
span_err!(self.session, ident.span, E0603, "{} `{}` is private",

src/librustc_resolve/macros.rs

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
// except according to those terms.
1010

1111
use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
12-
use {CrateLint, DeterminacyExt, Resolver, ResolutionError, is_known_tool, resolve_error};
12+
use {CrateLint, DeterminacyExt, Resolver, ResolutionError};
1313
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
14+
use {is_known_tool, names_to_string, resolve_error};
1415
use ModuleOrUniformRoot;
1516
use Namespace::{self, *};
1617
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
@@ -450,6 +451,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
450451
return Err(Determinacy::Determined);
451452
}
452453
}
454+
Def::Err => {
455+
return Err(Determinacy::Determined);
456+
}
453457
_ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"),
454458
}
455459

@@ -476,29 +480,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
476480
if path.len() > 1 {
477481
let def = match self.resolve_path(&path, Some(MacroNS), parent_scope,
478482
false, path_span, CrateLint::No) {
479-
PathResult::NonModule(path_res) => match path_res.base_def() {
480-
Def::Err => Err(Determinacy::Determined),
481-
def @ _ => {
482-
if path_res.unresolved_segments() > 0 {
483-
self.found_unresolved_macro = true;
484-
self.session.span_err(path_span,
485-
"fail to resolve non-ident macro path");
486-
Err(Determinacy::Determined)
487-
} else {
488-
Ok(def)
489-
}
490-
}
491-
},
492-
PathResult::Module(..) => unreachable!(),
483+
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
484+
Ok(path_res.base_def())
485+
}
493486
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
494-
_ => {
487+
PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => {
495488
self.found_unresolved_macro = true;
496489
Err(Determinacy::Determined)
497-
},
490+
}
491+
PathResult::Module(..) => unreachable!(),
498492
};
499493

500-
parent_scope.module.macro_resolutions.borrow_mut()
501-
.push((path, parent_scope.clone(), path_span));
494+
parent_scope.module.multi_segment_macro_resolutions.borrow_mut()
495+
.push((path, path_span, kind, parent_scope.clone(), def.ok()));
502496

503497
def
504498
} else {
@@ -511,7 +505,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
511505
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
512506
}
513507

514-
parent_scope.module.legacy_macro_resolutions.borrow_mut()
508+
parent_scope.module.single_segment_macro_resolutions.borrow_mut()
515509
.push((path[0], kind, parent_scope.clone(), binding.ok()));
516510

517511
binding.map(|binding| binding.def_ignoring_ambiguity())
@@ -912,48 +906,66 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
912906
pub fn finalize_current_module_macro_resolutions(&mut self) {
913907
let module = self.current_module;
914908

909+
let check_consistency = |this: &mut Self, path: &[Ident], span,
910+
kind: MacroKind, initial_def, def| {
911+
if let Some(initial_def) = initial_def {
912+
if def != initial_def && def != Def::Err && this.ambiguity_errors.is_empty() {
913+
// Make sure compilation does not succeed if preferred macro resolution
914+
// has changed after the macro had been expanded. In theory all such
915+
// situations should be reported as ambiguity errors, so this is a bug.
916+
span_bug!(span, "inconsistent resolution for a macro");
917+
}
918+
} else {
919+
// It's possible that the macro was unresolved (indeterminate) and silently
920+
// expanded into a dummy fragment for recovery during expansion.
921+
// Now, post-expansion, the resolution may succeed, but we can't change the
922+
// past and need to report an error.
923+
// However, non-speculative `resolve_path` can successfully return private items
924+
// even if speculative `resolve_path` returned nothing previously, so we skip this
925+
// less informative error if the privacy error is reported elsewhere.
926+
if this.privacy_errors.is_empty() {
927+
let msg = format!("cannot determine resolution for the {} `{}`",
928+
kind.descr(), names_to_string(path));
929+
let msg_note = "import resolution is stuck, try simplifying macro imports";
930+
this.session.struct_span_err(span, &msg).note(msg_note).emit();
931+
}
932+
}
933+
};
934+
915935
let macro_resolutions =
916-
mem::replace(&mut *module.macro_resolutions.borrow_mut(), Vec::new());
917-
for (path, parent_scope, path_span) in macro_resolutions {
936+
mem::replace(&mut *module.multi_segment_macro_resolutions.borrow_mut(), Vec::new());
937+
for (path, path_span, kind, parent_scope, initial_def) in macro_resolutions {
918938
match self.resolve_path(&path, Some(MacroNS), &parent_scope,
919939
true, path_span, CrateLint::No) {
920-
PathResult::NonModule(_) => {},
921-
PathResult::Failed(span, msg, _) => {
940+
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
941+
let def = path_res.base_def();
942+
check_consistency(self, &path, path_span, kind, initial_def, def);
943+
}
944+
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed(..) => {
945+
let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res {
946+
(span, msg)
947+
} else {
948+
(path_span, format!("partially resolved path in {} {}",
949+
kind.article(), kind.descr()))
950+
};
922951
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
923952
}
924-
_ => unreachable!(),
953+
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
925954
}
926955
}
927956

928-
let legacy_macro_resolutions =
929-
mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
930-
for (ident, kind, parent_scope, initial_binding) in legacy_macro_resolutions {
931-
let binding = self.early_resolve_ident_in_lexical_scope(
932-
ident, MacroNS, Some(kind), false, &parent_scope, true, true, ident.span
933-
);
934-
match binding {
957+
let macro_resolutions =
958+
mem::replace(&mut *module.single_segment_macro_resolutions.borrow_mut(), Vec::new());
959+
for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
960+
match self.early_resolve_ident_in_lexical_scope(ident, MacroNS, Some(kind), false,
961+
&parent_scope, true, true, ident.span) {
935962
Ok(binding) => {
936-
let def = binding.def_ignoring_ambiguity();
937-
if let Some(initial_binding) = initial_binding {
963+
let initial_def = initial_binding.map(|initial_binding| {
938964
self.record_use(ident, MacroNS, initial_binding);
939-
let initial_def = initial_binding.def_ignoring_ambiguity();
940-
if self.ambiguity_errors.is_empty() &&
941-
def != initial_def && def != Def::Err {
942-
// Make sure compilation does not succeed if preferred macro resolution
943-
// has changed after the macro had been expanded. In theory all such
944-
// situations should be reported as ambiguity errors, so this is a bug.
945-
span_bug!(ident.span, "inconsistent resolution for a macro");
946-
}
947-
} else {
948-
// It's possible that the macro was unresolved (indeterminate) and silently
949-
// expanded into a dummy fragment for recovery during expansion.
950-
// Now, post-expansion, the resolution may succeed, but we can't change the
951-
// past and need to report an error.
952-
let msg = format!("cannot determine resolution for the {} `{}`",
953-
kind.descr(), ident);
954-
let msg_note = "import resolution is stuck, try simplifying macro imports";
955-
self.session.struct_span_err(ident.span, &msg).note(msg_note).emit();
956-
}
965+
initial_binding.def_ignoring_ambiguity()
966+
});
967+
let def = binding.def_ignoring_ambiguity();
968+
check_consistency(self, &[ident], ident.span, kind, initial_def, def);
957969
}
958970
Err(..) => {
959971
assert!(initial_binding.is_none());

0 commit comments

Comments
 (0)