Skip to content

Commit

Permalink
Add one more prelude layer for extern crate names passed with --extern
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Apr 26, 2018
1 parent 7f3444e commit c1492fe
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 8 deletions.
36 changes: 29 additions & 7 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,7 @@ pub struct Resolver<'a> {
graph_root: Module<'a>,

prelude: Option<Module<'a>>,
extern_prelude: FxHashSet<Name>,

/// n.b. This is used only for better diagnostics, not name resolution itself.
has_self: FxHashSet<DefId>,
Expand Down Expand Up @@ -1715,6 +1716,7 @@ impl<'a> Resolver<'a> {
// AST.
graph_root,
prelude: None,
extern_prelude: session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect(),

has_self: FxHashSet(),
field_names: FxHashMap(),
Expand Down Expand Up @@ -1970,13 +1972,32 @@ impl<'a> Resolver<'a> {
}
}

match self.prelude {
Some(prelude) if !module.no_implicit_prelude => {
self.resolve_ident_in_module_unadjusted(prelude, ident, ns, false, false, path_span)
.ok().map(LexicalScopeBinding::Item)
if !module.no_implicit_prelude {
// `record_used` means that we don't try to load crates during speculative resolution
if record_used && ns == TypeNS && self.extern_prelude.contains(&ident.name) {
if !self.session.features_untracked().extern_prelude {
feature_err(&self.session.parse_sess, "extern_prelude",
ident.span, GateIssue::Language,
"access to extern crates through prelude is experimental").emit();
}

let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(crate_root);

let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
}
if let Some(prelude) = self.prelude {
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
false, false, path_span) {
return Some(LexicalScopeBinding::Item(binding));
}
}
_ => None,
}

None
}

fn hygienic_lexical_parent(&mut self, mut module: Module<'a>, span: &mut Span)
Expand Down Expand Up @@ -3587,8 +3608,9 @@ impl<'a> Resolver<'a> {
// We can see through blocks
} else {
// Items from the prelude
if let Some(prelude) = self.prelude {
if !module.no_implicit_prelude {
if !module.no_implicit_prelude {
names.extend(self.extern_prelude.iter().cloned());
if let Some(prelude) = self.prelude {
add_module_candidates(prelude, &mut names);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ declare_features! (
(active, generic_associated_types, "1.23.0", Some(44265), None),

// Resolve absolute paths as paths from other crates
(active, extern_absolute_paths, "1.24.0", Some(44660), None),
(active, extern_absolute_paths, "1.24.0", Some(44660), Some(Edition::Edition2018)),

// `foo.rs` as an alternative to `foo/mod.rs`
(active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
Expand Down Expand Up @@ -466,6 +466,9 @@ declare_features! (

// #[doc(alias = "...")]
(active, doc_alias, "1.27.0", Some(50146), None),

// Access to crate names passed via `--extern` through prelude
(active, extern_prelude, "1.27.0", Some(44660), Some(Edition::Edition2018)),
);

declare_features! (
Expand Down
12 changes: 12 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-include ../tools.mk

all:
$(RUSTC) ep-lib.rs
$(RUSTC) ep-vec.rs

$(RUSTC) basic.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib
$(RUSTC) shadow-mod.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib
$(RUSTC) shadow-prelude.rs --extern Vec=$(TMPDIR)/libep_vec.rlib
$(RUSTC) feature-gate.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "access to extern crates through prelude is experimental"
$(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "unresolved import"
$(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "failed to resolve"
16 changes: 16 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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.

#![feature(extern_prelude)]

fn main() {
let s = ep_lib::S; // It works
s.external();
}
17 changes: 17 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/ep-lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2017 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.

#![crate_type = "rlib"]

pub struct S;

impl S {
pub fn external(&self) {}
}
13 changes: 13 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/ep-vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2017 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.

#![crate_type = "rlib"]

pub fn new(arg1: f32, arg2: ()) {}
13 changes: 13 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/feature-gate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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.

fn main() {
let s = ep_lib::S; // Feature error
}
19 changes: 19 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/relative-only.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.

// Extern prelude names are not available by absolute paths

#![feature(extern_prelude)]

use ep_lib::S;

fn main() {
let s = ::ep_lib::S;
}
24 changes: 24 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/shadow-mod.rs
Original file line number Diff line number Diff line change
@@ -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.

// Local module shadows `ep_lib` from extern prelude

mod ep_lib {
pub struct S;

impl S {
pub fn internal(&self) {}
}
}

fn main() {
let s = ep_lib::S;
s.internal(); // OK
}
17 changes: 17 additions & 0 deletions src/test/run-make-fulldeps/extern-prelude/shadow-prelude.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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.

// Extern prelude shadows standard library prelude

#![feature(extern_prelude)]

fn main() {
let x = Vec::new(0f32, ()); // OK
}
21 changes: 21 additions & 0 deletions src/test/run-pass/extern-prelude-no-speculative.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2014 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.

// compile-flags: --extern LooksLikeExternCrate=/path/to/nowhere

mod m {
pub struct LooksLikeExternCrate;
}

fn main() {
// OK, speculative resolution for `unused_qualifications` doesn't try
// to resolve this as an extern crate and load that crate
let s = m::LooksLikeExternCrate {};
}
11 changes: 11 additions & 0 deletions src/test/ui/feature-gate-extern_prelude.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// 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.

can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-`
8 changes: 8 additions & 0 deletions src/test/ui/feature-gate-extern_prelude.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: expected one of `!` or `::`, found `-`
--> $DIR/feature-gate-extern_prelude.rs:11:4
|
LL | can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-`
| ^ expected one of `!` or `::` here

error: aborting due to previous error

0 comments on commit c1492fe

Please sign in to comment.