Skip to content

Commit 063553f

Browse files
committed
resolve: Avoid "self-confirming" resolutions in import validation
1 parent 2bde39b commit 063553f

File tree

5 files changed

+46
-36
lines changed

5 files changed

+46
-36
lines changed

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
230230
}
231231

232232
let subclass = SingleImport {
233-
target: ident,
234233
source: source.ident,
235-
result: PerNS {
234+
target: ident,
235+
source_bindings: PerNS {
236236
type_ns: Cell::new(Err(Undetermined)),
237237
value_ns: Cell::new(Err(Undetermined)),
238238
macro_ns: Cell::new(Err(Undetermined)),
239239
},
240+
target_bindings: PerNS {
241+
type_ns: Cell::new(None),
242+
value_ns: Cell::new(None),
243+
macro_ns: Cell::new(None),
244+
},
240245
type_ns_only,
241246
};
242247
self.add_import_directive(

src/librustc_resolve/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,6 +1521,7 @@ pub struct Resolver<'a, 'b: 'a> {
15211521

15221522
/// FIXME: Refactor things so that this is passed through arguments and not resolver.
15231523
last_import_segment: bool,
1524+
blacklisted_binding: Option<&'a NameBinding<'a>>,
15241525

15251526
/// The idents for the primitive types.
15261527
primitive_type_table: PrimitiveTypeTable,
@@ -1871,6 +1872,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
18711872
current_self_type: None,
18721873
current_self_item: None,
18731874
last_import_segment: false,
1875+
blacklisted_binding: None,
18741876

18751877
primitive_type_table: PrimitiveTypeTable::new(),
18761878

src/librustc_resolve/macros.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -977,12 +977,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
977977
let what = self.binding_description(binding, ident,
978978
flags.contains(Flags::MISC_FROM_PRELUDE));
979979
let note_msg = format!("this import refers to {what}", what = what);
980-
if binding.span.is_dummy() {
980+
let label_span = if binding.span.is_dummy() {
981981
err.note(&note_msg);
982+
ident.span
982983
} else {
983984
err.span_note(binding.span, &note_msg);
984-
err.span_label(binding.span, "not an extern crate passed with `--extern`");
985-
}
985+
binding.span
986+
};
987+
err.span_label(label_span, "not an extern crate passed with `--extern`");
986988
err.emit();
987989
}
988990

src/librustc_resolve/resolve_imports.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ use std::{mem, ptr};
4242
#[derive(Clone, Debug)]
4343
pub enum ImportDirectiveSubclass<'a> {
4444
SingleImport {
45-
target: Ident,
4645
source: Ident,
47-
result: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
46+
target: Ident,
47+
source_bindings: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
48+
target_bindings: PerNS<Cell<Option<&'a NameBinding<'a>>>>,
4849
type_ns_only: bool,
4950
},
5051
GlobImport {
@@ -227,6 +228,11 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
227228
}
228229

229230
let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
231+
if let Some(blacklisted_binding) = this.blacklisted_binding {
232+
if ptr::eq(binding, blacklisted_binding) {
233+
return Err((Determined, Weak::No));
234+
}
235+
}
230236
// `extern crate` are always usable for backwards compatibility, see issue #37020,
231237
// remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`.
232238
let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
@@ -646,10 +652,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
646652
if let Some((span, err, note)) = self.finalize_import(import) {
647653
errors = true;
648654

649-
if let SingleImport { source, ref result, .. } = import.subclass {
655+
if let SingleImport { source, ref source_bindings, .. } = import.subclass {
650656
if source.name == "self" {
651657
// Silence `unresolved import` error if E0429 is already emitted
652-
if let Err(Determined) = result.value_ns.get() {
658+
if let Err(Determined) = source_bindings.value_ns.get() {
653659
continue;
654660
}
655661
}
@@ -769,9 +775,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
769775
};
770776

771777
directive.imported_module.set(Some(module));
772-
let (source, target, result, type_ns_only) = match directive.subclass {
773-
SingleImport { source, target, ref result, type_ns_only } =>
774-
(source, target, result, type_ns_only),
778+
let (source, target, source_bindings, target_bindings, type_ns_only) =
779+
match directive.subclass {
780+
SingleImport { source, target, ref source_bindings,
781+
ref target_bindings, type_ns_only } =>
782+
(source, target, source_bindings, target_bindings, type_ns_only),
775783
GlobImport { .. } => {
776784
self.resolve_glob_import(directive);
777785
return true;
@@ -781,7 +789,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
781789

782790
let mut indeterminate = false;
783791
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
784-
if let Err(Undetermined) = result[ns].get() {
792+
if let Err(Undetermined) = source_bindings[ns].get() {
785793
// For better failure detection, pretend that the import will
786794
// not define any names while resolving its module path.
787795
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
@@ -790,13 +798,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
790798
);
791799
directive.vis.set(orig_vis);
792800

793-
result[ns].set(binding);
801+
source_bindings[ns].set(binding);
794802
} else {
795803
return
796804
};
797805

798806
let parent = directive.parent_scope.module;
799-
match result[ns].get() {
807+
match source_bindings[ns].get() {
800808
Err(Undetermined) => indeterminate = true,
801809
Err(Determined) => {
802810
this.update_resolution(parent, target, ns, |_, resolution| {
@@ -814,6 +822,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
814822
}
815823
Ok(binding) => {
816824
let imported_binding = this.import(binding, directive);
825+
target_bindings[ns].set(Some(imported_binding));
817826
let conflict = this.try_define(parent, target, ns, imported_binding);
818827
if let Err(old_binding) = conflict {
819828
this.report_conflict(parent, target, ns, imported_binding, old_binding);
@@ -885,8 +894,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
885894
PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(),
886895
};
887896

888-
let (ident, result, type_ns_only) = match directive.subclass {
889-
SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only),
897+
let (ident, source_bindings, target_bindings, type_ns_only) = match directive.subclass {
898+
SingleImport { source, ref source_bindings, ref target_bindings, type_ns_only, .. } =>
899+
(source, source_bindings, target_bindings, type_ns_only),
890900
GlobImport { is_prelude, ref max_vis } => {
891901
if directive.module_path.len() <= 1 {
892902
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
@@ -925,17 +935,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
925935
let mut all_ns_err = true;
926936
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
927937
let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
938+
let orig_blacklisted_binding =
939+
mem::replace(&mut this.blacklisted_binding, target_bindings[ns].get());
928940
let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true);
929941
let binding = this.resolve_ident_in_module(
930942
module, ident, ns, Some(&directive.parent_scope), true, directive.span
931943
);
932944
this.last_import_segment = orig_last_import_segment;
945+
this.blacklisted_binding = orig_blacklisted_binding;
933946
directive.vis.set(orig_vis);
934947

935948
match binding {
936949
Ok(binding) => {
937950
// Consistency checks, analogous to `finalize_current_module_macro_resolutions`.
938-
let initial_def = result[ns].get().map(|initial_binding| {
951+
let initial_def = source_bindings[ns].get().map(|initial_binding| {
939952
all_ns_err = false;
940953
this.record_use(ident, ns, initial_binding,
941954
directive.module_path.is_empty());
@@ -1040,7 +1053,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10401053
let mut reexport_error = None;
10411054
let mut any_successful_reexport = false;
10421055
self.per_ns(|this, ns| {
1043-
if let Ok(binding) = result[ns].get() {
1056+
if let Ok(binding) = source_bindings[ns].get() {
10441057
let vis = directive.vis.get();
10451058
if !binding.pseudo_vis().is_at_least(vis, &*this) {
10461059
reexport_error = Some((ns, binding));
@@ -1084,7 +1097,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10841097
let mut full_path = directive.module_path.clone();
10851098
full_path.push(Segment::from_ident(ident));
10861099
self.per_ns(|this, ns| {
1087-
if let Ok(binding) = result[ns].get() {
1100+
if let Ok(binding) = source_bindings[ns].get() {
10881101
this.lint_if_path_starts_with_module(
10891102
directive.crate_lint(),
10901103
&full_path,
@@ -1098,7 +1111,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10981111
// Record what this import resolves to for later uses in documentation,
10991112
// this may resolve to either a value or a type, but for documentation
11001113
// purposes it's good enough to just favor one over the other.
1101-
self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
1114+
self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
11021115
let mut def = binding.def();
11031116
if let Def::Macro(def_id, _) = def {
11041117
// `DefId`s from the "built-in macro crate" should not leak from resolve because

src/test/ui/feature-gates/feature-gate-uniform-paths.stderr

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@ LL | use inline; //~ ERROR imports can only refer to extern crate names
2525
| ^^^^^^ not an extern crate passed with `--extern`
2626
|
2727
= help: add #![feature(uniform_paths)] to the crate attributes to enable
28-
note: this import refers to the built-in attribute imported here
29-
--> $DIR/feature-gate-uniform-paths.rs:21:5
30-
|
31-
LL | use inline; //~ ERROR imports can only refer to extern crate names
32-
| ^^^^^^
28+
= note: this import refers to a built-in attribute
3329

3430
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
3531
--> $DIR/feature-gate-uniform-paths.rs:23:5
@@ -38,11 +34,7 @@ LL | use Vec; //~ ERROR imports can only refer to extern crate names
3834
| ^^^ not an extern crate passed with `--extern`
3935
|
4036
= help: add #![feature(uniform_paths)] to the crate attributes to enable
41-
note: this import refers to the struct imported here
42-
--> $DIR/feature-gate-uniform-paths.rs:23:5
43-
|
44-
LL | use Vec; //~ ERROR imports can only refer to extern crate names
45-
| ^^^
37+
= note: this import refers to a struct from prelude
4638

4739
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
4840
--> $DIR/feature-gate-uniform-paths.rs:25:5
@@ -51,11 +43,7 @@ LL | use vec; //~ ERROR imports can only refer to extern crate names
5143
| ^^^ not an extern crate passed with `--extern`
5244
|
5345
= help: add #![feature(uniform_paths)] to the crate attributes to enable
54-
note: this import refers to the macro imported here
55-
--> $DIR/feature-gate-uniform-paths.rs:25:5
56-
|
57-
LL | use vec; //~ ERROR imports can only refer to extern crate names
58-
| ^^^
46+
= note: this import refers to a macro from prelude
5947

6048
error: aborting due to 4 previous errors
6149

0 commit comments

Comments
 (0)