Auto merge of #54011 - eddyb:anchored-in-the-future, r=petrochenkov
rustc_resolve: inject `uniform_paths` canaries regardless of the feature-gate, on Rust 2018. This PR is an attempt at future-proofing "anchored paths" by emitting the same ambiguity errors that `#![feature(uniform_paths)]` would, with slightly changed phrasing (see added UI tests). Also, on top of #54005, this PR allows this as well: ```rust use crate_name; use crate_name::foo; ``` In that any ambiguity between an extern crate and an import *of that same crate* is ignored. r? @petrochenkov cc @aturon @Centril @joshtriplett
This commit is contained in:
commit
595345419d
15 changed files with 307 additions and 48 deletions
|
@ -194,27 +194,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
// ergonomically unacceptable.
|
// ergonomically unacceptable.
|
||||||
let emit_uniform_paths_canary =
|
let emit_uniform_paths_canary =
|
||||||
!uniform_paths_canary_emitted &&
|
!uniform_paths_canary_emitted &&
|
||||||
uniform_paths &&
|
self.session.rust_2018() &&
|
||||||
starts_with_non_keyword;
|
starts_with_non_keyword;
|
||||||
if emit_uniform_paths_canary {
|
if emit_uniform_paths_canary {
|
||||||
let source = prefix_start.unwrap();
|
let source = prefix_start.unwrap();
|
||||||
|
|
||||||
// HACK(eddyb) For `use x::{self, ...};`, use the ID of the
|
|
||||||
// `self` nested import for the canary. This allows the
|
|
||||||
// ambiguity reporting scope to ignore false positives
|
|
||||||
// in the same way it does for `use x;` (by comparing IDs).
|
|
||||||
let mut canary_id = id;
|
|
||||||
if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
|
|
||||||
for &(ref use_tree, id) in items {
|
|
||||||
if let ast::UseTreeKind::Simple(..) = use_tree.kind {
|
|
||||||
if use_tree.ident().name == keywords::SelfValue.name() {
|
|
||||||
canary_id = id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper closure to emit a canary with the given base path.
|
// Helper closure to emit a canary with the given base path.
|
||||||
let emit = |this: &mut Self, base: Option<Ident>| {
|
let emit = |this: &mut Self, base: Option<Ident>| {
|
||||||
let subclass = SingleImport {
|
let subclass = SingleImport {
|
||||||
|
@ -234,7 +218,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
||||||
base.into_iter().collect(),
|
base.into_iter().collect(),
|
||||||
subclass.clone(),
|
subclass.clone(),
|
||||||
source.span,
|
source.span,
|
||||||
canary_id,
|
id,
|
||||||
root_use_tree.span,
|
root_use_tree.span,
|
||||||
root_id,
|
root_id,
|
||||||
ty::Visibility::Invisible,
|
ty::Visibility::Invisible,
|
||||||
|
|
|
@ -620,9 +620,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct UniformPathsCanaryResult {
|
struct UniformPathsCanaryResult<'a> {
|
||||||
module_scope: Option<Span>,
|
module_scope: Option<&'a NameBinding<'a>>,
|
||||||
block_scopes: Vec<Span>,
|
block_scopes: Vec<&'a NameBinding<'a>>,
|
||||||
}
|
}
|
||||||
// Collect all tripped `uniform_paths` canaries separately.
|
// Collect all tripped `uniform_paths` canaries separately.
|
||||||
let mut uniform_paths_canaries: BTreeMap<
|
let mut uniform_paths_canaries: BTreeMap<
|
||||||
|
@ -663,20 +663,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
|
|
||||||
self.per_ns(|_, ns| {
|
self.per_ns(|_, ns| {
|
||||||
if let Some(result) = result[ns].get().ok() {
|
if let Some(result) = result[ns].get().ok() {
|
||||||
if let NameBindingKind::Import { directive, .. } = result.kind {
|
|
||||||
// Skip canaries that resolve to the import itself.
|
|
||||||
// These come from `use crate_name;`, which isn't really
|
|
||||||
// ambiguous, as the import can't actually shadow itself.
|
|
||||||
if directive.id == import.id {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if has_explicit_self {
|
if has_explicit_self {
|
||||||
// There should only be one `self::x` (module-scoped) canary.
|
// There should only be one `self::x` (module-scoped) canary.
|
||||||
assert_eq!(canary_results[ns].module_scope, None);
|
assert!(canary_results[ns].module_scope.is_none());
|
||||||
canary_results[ns].module_scope = Some(result.span);
|
canary_results[ns].module_scope = Some(result);
|
||||||
} else {
|
} else {
|
||||||
canary_results[ns].block_scopes.push(result.span);
|
canary_results[ns].block_scopes.push(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -716,18 +708,39 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let uniform_paths_feature = self.session.features_untracked().uniform_paths;
|
||||||
for ((span, _), (name, results)) in uniform_paths_canaries {
|
for ((span, _), (name, results)) in uniform_paths_canaries {
|
||||||
self.per_ns(|this, ns| {
|
self.per_ns(|this, ns| {
|
||||||
let results = &results[ns];
|
let external_crate = if ns == TypeNS && this.extern_prelude.contains(&name) {
|
||||||
|
let crate_id =
|
||||||
|
this.crate_loader.process_path_extern(name, span);
|
||||||
|
Some(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let result_filter = |result: &&NameBinding| {
|
||||||
|
// Ignore canaries that resolve to an import of the same crate.
|
||||||
|
// That is, we allow `use crate_name; use crate_name::foo;`.
|
||||||
|
if let Some(def_id) = external_crate {
|
||||||
|
if let Some(module) = result.module() {
|
||||||
|
if module.normal_ancestor_id == def_id {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let has_external_crate =
|
true
|
||||||
ns == TypeNS && this.extern_prelude.contains(&name);
|
};
|
||||||
|
let module_scope = results[ns].module_scope.filter(result_filter);
|
||||||
|
let block_scopes = || {
|
||||||
|
results[ns].block_scopes.iter().cloned().filter(result_filter)
|
||||||
|
};
|
||||||
|
|
||||||
// An ambiguity requires more than one possible resolution.
|
// An ambiguity requires more than one possible resolution.
|
||||||
let possible_resultions =
|
let possible_resultions =
|
||||||
(has_external_crate as usize) +
|
(external_crate.is_some() as usize) +
|
||||||
(results.module_scope.is_some() as usize) +
|
(module_scope.is_some() as usize) +
|
||||||
(!results.block_scopes.is_empty() as usize);
|
(block_scopes().next().is_some() as usize);
|
||||||
if possible_resultions <= 1 {
|
if possible_resultions <= 1 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -737,25 +750,34 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
let msg = format!("`{}` import is ambiguous", name);
|
let msg = format!("`{}` import is ambiguous", name);
|
||||||
let mut err = this.session.struct_span_err(span, &msg);
|
let mut err = this.session.struct_span_err(span, &msg);
|
||||||
let mut suggestion_choices = String::new();
|
let mut suggestion_choices = String::new();
|
||||||
if has_external_crate {
|
if external_crate.is_some() {
|
||||||
write!(suggestion_choices, "`::{}`", name);
|
write!(suggestion_choices, "`::{}`", name);
|
||||||
err.span_label(span,
|
err.span_label(span,
|
||||||
format!("can refer to external crate `::{}`", name));
|
format!("can refer to external crate `::{}`", name));
|
||||||
}
|
}
|
||||||
if let Some(span) = results.module_scope {
|
if let Some(result) = module_scope {
|
||||||
if !suggestion_choices.is_empty() {
|
if !suggestion_choices.is_empty() {
|
||||||
suggestion_choices.push_str(" or ");
|
suggestion_choices.push_str(" or ");
|
||||||
}
|
}
|
||||||
write!(suggestion_choices, "`self::{}`", name);
|
write!(suggestion_choices, "`self::{}`", name);
|
||||||
err.span_label(span,
|
if uniform_paths_feature {
|
||||||
format!("can refer to `self::{}`", name));
|
err.span_label(result.span,
|
||||||
|
format!("can refer to `self::{}`", name));
|
||||||
|
} else {
|
||||||
|
err.span_label(result.span,
|
||||||
|
format!("may refer to `self::{}` in the future", name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for &span in &results.block_scopes {
|
for result in block_scopes() {
|
||||||
err.span_label(span,
|
err.span_label(result.span,
|
||||||
format!("shadowed by block-scoped `{}`", name));
|
format!("shadowed by block-scoped `{}`", name));
|
||||||
}
|
}
|
||||||
err.help(&format!("write {} explicitly instead", suggestion_choices));
|
err.help(&format!("write {} explicitly instead", suggestion_choices));
|
||||||
err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`");
|
if uniform_paths_feature {
|
||||||
|
err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`");
|
||||||
|
} else {
|
||||||
|
err.note("in the future, `#![feature(uniform_paths)]` may become the default");
|
||||||
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -968,11 +990,15 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Do not record uses from canaries, to avoid interfering with other
|
||||||
|
// diagnostics or suggestions that rely on some items not being used.
|
||||||
|
let record_used = !directive.is_uniform_paths_canary;
|
||||||
|
|
||||||
let mut all_ns_err = true;
|
let mut all_ns_err = true;
|
||||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||||
if let Ok(binding) = result[ns].get() {
|
if let Ok(binding) = result[ns].get() {
|
||||||
all_ns_err = false;
|
all_ns_err = false;
|
||||||
if this.record_use(ident, ns, binding) {
|
if record_used && this.record_use(ident, ns, binding) {
|
||||||
if let ModuleOrUniformRoot::Module(module) = module {
|
if let ModuleOrUniformRoot::Module(module) = module {
|
||||||
this.resolution(module, ident, ns).borrow_mut().binding =
|
this.resolution(module, ident, ns).borrow_mut().binding =
|
||||||
Some(this.dummy_binding);
|
Some(this.dummy_binding);
|
||||||
|
@ -984,7 +1010,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
|
||||||
if all_ns_err {
|
if all_ns_err {
|
||||||
let mut all_ns_failed = true;
|
let mut all_ns_failed = true;
|
||||||
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
|
||||||
match this.resolve_ident_in_module(module, ident, ns, true, span) {
|
match this.resolve_ident_in_module(module, ident, ns, record_used, span) {
|
||||||
Ok(_) => all_ns_failed = false,
|
Ok(_) => all_ns_failed = false,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
// This test is similar to `ambiguity-macros.rs`, but nested in a module.
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
pub use std::io;
|
||||||
|
//~^ ERROR `std` import is ambiguous
|
||||||
|
|
||||||
|
macro_rules! m {
|
||||||
|
() => {
|
||||||
|
mod std {
|
||||||
|
pub struct io;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,16 @@
|
||||||
|
error: `std` import is ambiguous
|
||||||
|
--> $DIR/ambiguity-macros-nested.rs:16:13
|
||||||
|
|
|
||||||
|
LL | pub use std::io;
|
||||||
|
| ^^^ can refer to external crate `::std`
|
||||||
|
...
|
||||||
|
LL | / mod std {
|
||||||
|
LL | | pub struct io;
|
||||||
|
LL | | }
|
||||||
|
| |_____________- may refer to `self::std` in the future
|
||||||
|
|
|
||||||
|
= help: write `::std` or `self::std` explicitly instead
|
||||||
|
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
// This test is similar to `ambiguity.rs`, but with macros defining local items.
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
//~^ ERROR `std` import is ambiguous
|
||||||
|
|
||||||
|
macro_rules! m {
|
||||||
|
() => {
|
||||||
|
mod std {
|
||||||
|
pub struct io;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m!();
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,16 @@
|
||||||
|
error: `std` import is ambiguous
|
||||||
|
--> $DIR/ambiguity-macros.rs:15:5
|
||||||
|
|
|
||||||
|
LL | use std::io;
|
||||||
|
| ^^^ can refer to external crate `::std`
|
||||||
|
...
|
||||||
|
LL | / mod std {
|
||||||
|
LL | | pub struct io;
|
||||||
|
LL | | }
|
||||||
|
| |_________- may refer to `self::std` in the future
|
||||||
|
|
|
||||||
|
= help: write `::std` or `self::std` explicitly instead
|
||||||
|
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
// This test is similar to `ambiguity.rs`, but nested in a module.
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
pub use std::io;
|
||||||
|
//~^ ERROR `std` import is ambiguous
|
||||||
|
|
||||||
|
mod std {
|
||||||
|
pub struct io;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,16 @@
|
||||||
|
error: `std` import is ambiguous
|
||||||
|
--> $DIR/ambiguity-nested.rs:16:13
|
||||||
|
|
|
||||||
|
LL | pub use std::io;
|
||||||
|
| ^^^ can refer to external crate `::std`
|
||||||
|
...
|
||||||
|
LL | / mod std {
|
||||||
|
LL | | pub struct io;
|
||||||
|
LL | | }
|
||||||
|
| |_____- may refer to `self::std` in the future
|
||||||
|
|
|
||||||
|
= help: write `::std` or `self::std` explicitly instead
|
||||||
|
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
//~^ ERROR `std` import is ambiguous
|
||||||
|
|
||||||
|
mod std {
|
||||||
|
pub struct io;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,16 @@
|
||||||
|
error: `std` import is ambiguous
|
||||||
|
--> $DIR/ambiguity.rs:13:5
|
||||||
|
|
|
||||||
|
LL | use std::io;
|
||||||
|
| ^^^ can refer to external crate `::std`
|
||||||
|
...
|
||||||
|
LL | / mod std {
|
||||||
|
LL | | pub struct io;
|
||||||
|
LL | | }
|
||||||
|
| |_- may refer to `self::std` in the future
|
||||||
|
|
|
||||||
|
= help: write `::std` or `self::std` explicitly instead
|
||||||
|
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
struct std;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
fn std() {}
|
||||||
|
enum std {}
|
||||||
|
use std as foo;
|
||||||
|
//~^ ERROR `std` import is ambiguous
|
||||||
|
//~| ERROR `std` import is ambiguous
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
error: `std` import is ambiguous
|
||||||
|
--> $DIR/block-scoped-shadow.rs:18:9
|
||||||
|
|
|
||||||
|
LL | struct std;
|
||||||
|
| ----------- may refer to `self::std` in the future
|
||||||
|
...
|
||||||
|
LL | enum std {}
|
||||||
|
| ----------- shadowed by block-scoped `std`
|
||||||
|
LL | use std as foo;
|
||||||
|
| ^^^ can refer to external crate `::std`
|
||||||
|
|
|
||||||
|
= help: write `::std` or `self::std` explicitly instead
|
||||||
|
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||||
|
|
||||||
|
error: `std` import is ambiguous
|
||||||
|
--> $DIR/block-scoped-shadow.rs:18:9
|
||||||
|
|
|
||||||
|
LL | struct std;
|
||||||
|
| ----------- may refer to `self::std` in the future
|
||||||
|
...
|
||||||
|
LL | fn std() {}
|
||||||
|
| ----------- shadowed by block-scoped `std`
|
||||||
|
LL | enum std {}
|
||||||
|
LL | use std as foo;
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: write `self::std` explicitly instead
|
||||||
|
= note: in the future, `#![feature(uniform_paths)]` may become the default
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// run-pass
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
use std;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
pub use std as my_std;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod bar {
|
||||||
|
pub use std::{self};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
io::stdout();
|
||||||
|
self::std::io::stdout();
|
||||||
|
foo::my_std::io::stdout();
|
||||||
|
bar::std::io::stdout();
|
||||||
|
}
|
|
@ -8,11 +8,13 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// run-pass
|
||||||
// edition:2018
|
// edition:2018
|
||||||
|
|
||||||
#![feature(uniform_paths)]
|
#![feature(uniform_paths)]
|
||||||
|
|
||||||
use std;
|
use std;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
mod foo {
|
mod foo {
|
||||||
pub use std as my_std;
|
pub use std as my_std;
|
||||||
|
@ -23,6 +25,7 @@ mod bar {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
io::stdout();
|
||||||
self::std::io::stdout();
|
self::std::io::stdout();
|
||||||
foo::my_std::io::stdout();
|
foo::my_std::io::stdout();
|
||||||
bar::std::io::stdout();
|
bar::std::io::stdout();
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5b5cd9d45719414196e254ec17baa598acc8cd25
|
Subproject commit fa922de1e5e1f02b576b7a5aa6ded16935693ec5
|
Loading…
Add table
Add a link
Reference in a new issue