Skip to content

Commit c06e69e

Browse files
committed
resolve: Fallback to uniform paths in 2015 imports used from global 2018 edition
1 parent dae4c7b commit c06e69e

9 files changed

+186
-37
lines changed

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
132132
// so prefixes are prepended with crate root segment if necessary.
133133
// The root is prepended lazily, when the first non-empty prefix or terminating glob
134134
// appears, so imports in braced groups can have roots prepended independently.
135+
// 2015 identifiers used on global 2018 edition enter special "virtual 2015 mode", don't
136+
// get crate root prepended, but get special treatment during in-scope resolution instead.
135137
let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false };
136138
let crate_root = match prefix_iter.peek() {
137-
Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => {
139+
Some(seg) if !seg.ident.is_path_segment_keyword() &&
140+
seg.ident.span.rust_2015() && self.session.rust_2015() => {
138141
Some(seg.ident.span.ctxt())
139142
}
140143
None if is_glob && use_tree.span.rust_2015() => {

src/librustc_resolve/lib.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
html_root_url = "https://doc.rust-lang.org/nightly/")]
1414

1515
#![feature(crate_visibility_modifier)]
16+
#![feature(label_break_value)]
1617
#![feature(nll)]
1718
#![feature(rustc_diagnostic_macros)]
1819
#![feature(slice_sort_by_cached_key)]
@@ -2191,28 +2192,45 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
21912192
fn resolve_ident_in_module(
21922193
&mut self,
21932194
module: ModuleOrUniformRoot<'a>,
2194-
mut ident: Ident,
2195+
ident: Ident,
21952196
ns: Namespace,
21962197
parent_scope: Option<&ParentScope<'a>>,
21972198
record_used: bool,
21982199
path_span: Span
21992200
) -> Result<&'a NameBinding<'a>, Determinacy> {
2200-
ident.span = ident.span.modern();
2201+
self.resolve_ident_in_module_ext(
2202+
module, ident, ns, parent_scope, record_used, path_span
2203+
).map_err(|(determinacy, _)| determinacy)
2204+
}
2205+
2206+
fn resolve_ident_in_module_ext(
2207+
&mut self,
2208+
module: ModuleOrUniformRoot<'a>,
2209+
mut ident: Ident,
2210+
ns: Namespace,
2211+
parent_scope: Option<&ParentScope<'a>>,
2212+
record_used: bool,
2213+
path_span: Span
2214+
) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
22012215
let orig_current_module = self.current_module;
22022216
match module {
22032217
ModuleOrUniformRoot::Module(module) => {
2218+
ident.span = ident.span.modern();
22042219
if let Some(def) = ident.span.adjust(module.expansion) {
22052220
self.current_module = self.macro_def_scope(def);
22062221
}
22072222
}
22082223
ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude) => {
2224+
ident.span = ident.span.modern();
22092225
ident.span.adjust(Mark::root());
22102226
}
2211-
_ => {}
2227+
ModuleOrUniformRoot::UniformRoot(UniformRootKind::CurrentScope) => {
2228+
// No adjustments
2229+
}
22122230
}
22132231
let result = self.resolve_ident_in_module_unadjusted_ext(
22142232
module, ident, ns, parent_scope, false, record_used, path_span,
2215-
).map_err(|(determinacy, _)| determinacy);
2233+
);
22162234
self.current_module = orig_current_module;
22172235
result
22182236
}

src/librustc_resolve/macros.rs

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
526526
// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
527527
crate fn early_resolve_ident_in_lexical_scope(
528528
&mut self,
529-
mut ident: Ident,
529+
orig_ident: Ident,
530530
ns: Namespace,
531531
macro_kind: Option<MacroKind>,
532532
is_import: bool,
@@ -582,6 +582,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
582582
enum WhereToResolve<'a> {
583583
DeriveHelpers,
584584
MacroRules(LegacyScope<'a>),
585+
CrateRoot,
585586
Module(Module<'a>),
586587
MacroUsePrelude,
587588
BuiltinMacros,
@@ -605,8 +606,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
605606

606607
assert!(force || !record_used); // `record_used` implies `force`
607608
assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind
608-
let rust_2015 = ident.span.rust_2015();
609-
ident = ident.modern();
609+
let rust_2015 = orig_ident.span.rust_2015();
610+
let mut ident = orig_ident.modern();
610611

611612
// Make sure `self`, `super` etc produce an error when passed to here.
612613
if ident.is_path_segment_keyword() {
@@ -627,10 +628,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
627628
let mut innermost_result: Option<(&NameBinding, Flags)> = None;
628629

629630
// Go through all the scopes and try to resolve the name.
630-
let mut where_to_resolve = if ns == MacroNS {
631-
WhereToResolve::DeriveHelpers
632-
} else {
633-
WhereToResolve::Module(parent_scope.module)
631+
let mut where_to_resolve = match ns {
632+
_ if is_import && rust_2015 => WhereToResolve::CrateRoot,
633+
TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module),
634+
MacroNS => WhereToResolve::DeriveHelpers,
634635
};
635636
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
636637
let mut determinacy = Determinacy::Determined;
@@ -668,6 +669,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
668669
Err(Determinacy::Undetermined),
669670
_ => Err(Determinacy::Determined),
670671
}
672+
WhereToResolve::CrateRoot => {
673+
let root_ident = Ident::new(keywords::CrateRoot.name(), orig_ident.span);
674+
let root_module = self.resolve_crate_root(root_ident);
675+
let binding = self.resolve_ident_in_module_ext(
676+
ModuleOrUniformRoot::Module(root_module),
677+
orig_ident,
678+
ns,
679+
None,
680+
record_used,
681+
path_span,
682+
);
683+
match binding {
684+
Ok(binding) => Ok((binding, Flags::MODULE)),
685+
Err((Determinacy::Undetermined, Weak::No)) =>
686+
return Err(Determinacy::determined(force)),
687+
Err((Determinacy::Undetermined, Weak::Yes)) =>
688+
Err(Determinacy::Undetermined),
689+
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
690+
}
691+
}
671692
WhereToResolve::Module(module) => {
672693
let orig_current_module = mem::replace(&mut self.current_module, module);
673694
let binding = self.resolve_ident_in_module_unadjusted_ext(
@@ -816,7 +837,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
816837
} else if innermost_flags.contains(Flags::MACRO_RULES) &&
817838
flags.contains(Flags::MODULE) &&
818839
!self.disambiguate_legacy_vs_modern(innermost_binding,
819-
binding) {
840+
binding) ||
841+
flags.contains(Flags::MACRO_RULES) &&
842+
innermost_flags.contains(Flags::MODULE) &&
843+
!self.disambiguate_legacy_vs_modern(binding,
844+
innermost_binding) {
820845
Some(AmbiguityKind::LegacyVsModern)
821846
} else if innermost_binding.is_glob_import() {
822847
Some(AmbiguityKind::GlobVsOuter)
@@ -867,6 +892,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
867892
LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
868893
LegacyScope::Uninitialized => unreachable!(),
869894
}
895+
WhereToResolve::CrateRoot => match ns {
896+
TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module),
897+
MacroNS => WhereToResolve::DeriveHelpers,
898+
}
870899
WhereToResolve::Module(module) => {
871900
match self.hygienic_lexical_parent(module, &mut ident.span) {
872901
Some(parent_module) => WhereToResolve::Module(parent_module),
@@ -899,30 +928,43 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
899928

900929
// The first found solution was the only one, return it.
901930
if let Some((binding, flags)) = innermost_result {
902-
if is_import && !self.session.features_untracked().uniform_paths {
903-
// We get to here only if there's no ambiguity, in ambiguous cases an error will
904-
// be reported anyway, so there's no reason to report an additional feature error.
905-
// The `binding` can actually be introduced by something other than `--extern`,
906-
// but its `Def` should coincide with a crate passed with `--extern`
907-
// (otherwise there would be ambiguity) and we can skip feature error in this case.
908-
if ns != TypeNS || !use_prelude ||
909-
self.extern_prelude_get(ident, true).is_none() {
910-
let msg = "imports can only refer to extern crate names \
911-
passed with `--extern` on stable channel";
912-
let mut err = feature_err(&self.session.parse_sess, "uniform_paths",
913-
ident.span, GateIssue::Language, msg);
914-
915-
let what = self.binding_description(binding, ident,
916-
flags.contains(Flags::MISC_FROM_PRELUDE));
917-
let note_msg = format!("this import refers to {what}", what = what);
918-
if binding.span.is_dummy() {
919-
err.note(&note_msg);
920-
} else {
921-
err.span_note(binding.span, &note_msg);
922-
err.span_label(binding.span, "not an extern crate passed with `--extern`");
931+
// We get to here only if there's no ambiguity, in ambiguous cases an error will
932+
// be reported anyway, so there's no reason to report an additional feature error.
933+
// The `binding` can actually be introduced by something other than `--extern`,
934+
// but its `Def` should coincide with a crate passed with `--extern`
935+
// (otherwise there would be ambiguity) and we can skip feature error in this case.
936+
'ok: {
937+
if !is_import || self.session.features_untracked().uniform_paths {
938+
break 'ok;
939+
}
940+
if ns == TypeNS && use_prelude && self.extern_prelude_get(ident, true).is_some() {
941+
break 'ok;
942+
}
943+
if rust_2015 {
944+
let root_ident = Ident::new(keywords::CrateRoot.name(), orig_ident.span);
945+
let root_module = self.resolve_crate_root(root_ident);
946+
if self.resolve_ident_in_module_ext(ModuleOrUniformRoot::Module(root_module),
947+
orig_ident, ns, None, false, path_span)
948+
.is_ok() {
949+
break 'ok;
923950
}
924-
err.emit();
925951
}
952+
953+
let msg = "imports can only refer to extern crate names \
954+
passed with `--extern` on stable channel";
955+
let mut err = feature_err(&self.session.parse_sess, "uniform_paths",
956+
ident.span, GateIssue::Language, msg);
957+
958+
let what = self.binding_description(binding, ident,
959+
flags.contains(Flags::MISC_FROM_PRELUDE));
960+
let note_msg = format!("this import refers to {what}", what = what);
961+
if binding.span.is_dummy() {
962+
err.note(&note_msg);
963+
} else {
964+
err.span_note(binding.span, &note_msg);
965+
err.span_label(binding.span, "not an extern crate passed with `--extern`");
966+
}
967+
err.emit();
926968
}
927969

928970
return Ok(binding);

src/test/ui/editions/auxiliary/edition-imports-2015.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#[macro_export]
44
macro_rules! gen_imports { () => {
55
use import::Path;
6-
// use std::collections::LinkedList; // FIXME
6+
use std::collections::LinkedList;
77

88
fn check_absolute() {
99
::absolute::Path;
@@ -15,3 +15,16 @@ macro_rules! gen_imports { () => {
1515
macro_rules! gen_glob { () => {
1616
use *;
1717
}}
18+
19+
#[macro_export]
20+
macro_rules! gen_gated { () => {
21+
fn check_gated() {
22+
enum E { A }
23+
use E::*;
24+
}
25+
}}
26+
27+
#[macro_export]
28+
macro_rules! gen_ambiguous { () => {
29+
use Ambiguous;
30+
}}

src/test/ui/editions/edition-imports-2018.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod check {
1717

1818
fn check() {
1919
Path;
20-
// LinkedList::<u8>::new(); // FIXME
20+
LinkedList::<u8>::new();
2121
}
2222
}
2323

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// edition:2018
2+
// aux-build:edition-imports-2015.rs
3+
// error-pattern: `Ambiguous` is ambiguous
4+
5+
#[macro_use]
6+
extern crate edition_imports_2015;
7+
8+
pub struct Ambiguous {}
9+
10+
mod check {
11+
pub struct Ambiguous {}
12+
13+
fn check() {
14+
gen_ambiguous!();
15+
}
16+
}
17+
18+
fn main() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0659]: `Ambiguous` is ambiguous (name vs any other name during import resolution)
2+
--> <::edition_imports_2015::gen_ambiguous macros>:1:15
3+
|
4+
LL | ( ) => { use Ambiguous ; }
5+
| ^^^^^^^^^ ambiguous name
6+
|
7+
note: `Ambiguous` could refer to the struct defined here
8+
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:8:1
9+
|
10+
LL | pub struct Ambiguous {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^
12+
note: `Ambiguous` could also refer to the struct defined here
13+
--> $DIR/edition-imports-virtual-2015-ambiguity.rs:11:5
14+
|
15+
LL | pub struct Ambiguous {}
16+
| ^^^^^^^^^^^^^^^^^^^^^^^
17+
= help: use `self::Ambiguous` to refer to this struct unambiguously
18+
19+
error: aborting due to previous error
20+
21+
For more information about this error, try `rustc --explain E0659`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// edition:2018
2+
// aux-build:edition-imports-2015.rs
3+
// error-pattern: imports can only refer to extern crate names passed with `--extern`
4+
5+
#[macro_use]
6+
extern crate edition_imports_2015;
7+
8+
mod check {
9+
gen_gated!();
10+
}
11+
12+
fn main() {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130)
2+
--> <::edition_imports_2015::gen_gated macros>:1:50
3+
|
4+
LL | ( ) => { fn check_gated ( ) { enum E { A } use E :: * ; } }
5+
| ^
6+
|
7+
::: $DIR/edition-imports-virtual-2015-gated.rs:9:5
8+
|
9+
LL | gen_gated!();
10+
| ------------- not an extern crate passed with `--extern`
11+
|
12+
= help: add #![feature(uniform_paths)] to the crate attributes to enable
13+
note: this import refers to the enum defined here
14+
--> $DIR/edition-imports-virtual-2015-gated.rs:9:5
15+
|
16+
LL | gen_gated!();
17+
| ^^^^^^^^^^^^^
18+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)