Skip to content

Commit a48f958

Browse files
committed
Rollup merge of rust-lang#31362 - jseyfried:fix_extern_crate_visibility, r=nikomatsakis
This PR changes the visibility of extern crate declarations to match that of items (fixes rust-lang#26775). To avoid breakage, the PR makes it a `public_in_private` lint to reexport a private extern crate, and it adds the lint `inaccessible_extern_crate` for uses of an inaccessible extern crate. The lints can be avoided by making the appropriate `extern crate` declaration public.
2 parents f6f050d + 7ad7065 commit a48f958

File tree

16 files changed

+140
-72
lines changed

16 files changed

+140
-72
lines changed

src/librustc/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ extern crate getopts;
5151
extern crate graphviz;
5252
extern crate libc;
5353
extern crate rbml;
54-
extern crate rustc_llvm;
54+
pub extern crate rustc_llvm as llvm;
5555
extern crate rustc_back;
5656
extern crate rustc_front;
5757
extern crate rustc_data_structures;
@@ -66,8 +66,6 @@ extern crate serialize as rustc_serialize; // used by deriving
6666
#[cfg(test)]
6767
extern crate test;
6868

69-
pub use rustc_llvm as llvm;
70-
7169
#[macro_use]
7270
mod macros;
7371

src/librustc/lint/builtin.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ declare_lint! {
124124
"detect private items in public interfaces not caught by the old implementation"
125125
}
126126

127+
declare_lint! {
128+
pub INACCESSIBLE_EXTERN_CRATE,
129+
Warn,
130+
"use of inaccessible extern crate erroneously allowed"
131+
}
132+
127133
declare_lint! {
128134
pub INVALID_TYPE_PARAM_DEFAULT,
129135
Warn,
@@ -167,6 +173,7 @@ impl LintPass for HardwiredLints {
167173
TRIVIAL_CASTS,
168174
TRIVIAL_NUMERIC_CASTS,
169175
PRIVATE_IN_PUBLIC,
176+
INACCESSIBLE_EXTERN_CRATE,
170177
INVALID_TYPE_PARAM_DEFAULT,
171178
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
172179
CONST_ERR,

src/librustc_lint/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
158158
id: LintId::of(PRIVATE_IN_PUBLIC),
159159
reference: "the explanation for E0446 (`--explain E0446`)",
160160
},
161+
FutureIncompatibleInfo {
162+
id: LintId::of(INACCESSIBLE_EXTERN_CRATE),
163+
reference: "PR 31362 <https://github.com/rust-lang/rust/pull/31362>",
164+
},
161165
FutureIncompatibleInfo {
162166
id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
163167
reference: "PR 30742 <https://github.com/rust-lang/rust/pull/30724>",

src/librustc_privacy/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
743743
source_did: Option<DefId>,
744744
msg: &str)
745745
-> CheckResult {
746+
use rustc_front::hir::Item_::ItemExternCrate;
746747
debug!("ensure_public(span={:?}, to_check={:?}, source_did={:?}, msg={:?})",
747748
span, to_check, source_did, msg);
748749
let def_privacy = self.def_privacy(to_check);
@@ -763,6 +764,21 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
763764
// be local.)
764765
let def_id = source_did.unwrap_or(to_check);
765766
let node_id = self.tcx.map.as_local_node_id(def_id);
767+
768+
// Warn when using a inaccessible extern crate.
769+
if let Some(node_id) = self.tcx.map.as_local_node_id(to_check) {
770+
match self.tcx.map.get(node_id) {
771+
ast_map::Node::NodeItem(&hir::Item { node: ItemExternCrate(_), name, .. }) => {
772+
self.tcx.sess.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE,
773+
node_id,
774+
span,
775+
format!("extern crate `{}` is private", name));
776+
return None;
777+
}
778+
_ => {}
779+
}
780+
}
781+
766782
let (err_span, err_msg) = if Some(id) == node_id {
767783
return Some((span, format!("{} is private", msg), None));
768784
} else {

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,19 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
293293
self.external_exports.insert(def_id);
294294
let parent_link = ModuleParentLink(parent, name);
295295
let def = Def::Mod(def_id);
296-
let external_module = self.new_extern_crate_module(parent_link, def);
296+
let local_def_id = self.ast_map.local_def_id(item.id);
297+
let external_module =
298+
self.new_extern_crate_module(parent_link, def, is_public, local_def_id);
297299
self.define(parent, name, TypeNS, (external_module, sp));
298300

301+
if is_public {
302+
let export = Export { name: name, def_id: def_id };
303+
if let Some(def_id) = parent.def_id() {
304+
let node_id = self.resolver.ast_map.as_local_node_id(def_id).unwrap();
305+
self.export_map.entry(node_id).or_insert(Vec::new()).push(export);
306+
}
307+
}
308+
299309
self.build_reduced_graph_for_external_crate(external_module);
300310
}
301311
parent

src/librustc_resolve/lib.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,10 @@ pub struct ModuleS<'a> {
806806
parent_link: ParentLink<'a>,
807807
def: Option<Def>,
808808
is_public: bool,
809-
is_extern_crate: bool,
809+
810+
// If the module is an extern crate, `def` is root of the external crate and `extern_crate_did`
811+
// is the DefId of the local `extern crate` item (otherwise, `extern_crate_did` is None).
812+
extern_crate_did: Option<DefId>,
810813

811814
resolutions: RefCell<HashMap<(Name, Namespace), NameResolution<'a>>>,
812815
unresolved_imports: RefCell<Vec<ImportDirective>>,
@@ -853,7 +856,7 @@ impl<'a> ModuleS<'a> {
853856
parent_link: parent_link,
854857
def: def,
855858
is_public: is_public,
856-
is_extern_crate: false,
859+
extern_crate_did: None,
857860
resolutions: RefCell::new(HashMap::new()),
858861
unresolved_imports: RefCell::new(Vec::new()),
859862
module_children: RefCell::new(NodeMap()),
@@ -917,6 +920,16 @@ impl<'a> ModuleS<'a> {
917920
self.def.as_ref().map(Def::def_id)
918921
}
919922

923+
// This returns the DefId of the crate local item that controls this module's visibility.
924+
// It is only used to compute `LastPrivate` data, and it differs from `def_id` only for extern
925+
// crates, whose `def_id` is the external crate's root, not the local `extern crate` item.
926+
fn local_def_id(&self) -> Option<DefId> {
927+
match self.extern_crate_did {
928+
Some(def_id) => Some(def_id),
929+
None => self.def_id(),
930+
}
931+
}
932+
920933
fn is_normal(&self) -> bool {
921934
match self.def {
922935
Some(Def::Mod(_)) | Some(Def::ForeignMod(_)) => true,
@@ -1027,6 +1040,14 @@ impl<'a> NameBinding<'a> {
10271040
}
10281041
}
10291042

1043+
fn local_def_id(&self) -> Option<DefId> {
1044+
match self.kind {
1045+
NameBindingKind::Def(def) => Some(def.def_id()),
1046+
NameBindingKind::Module(ref module) => module.local_def_id(),
1047+
NameBindingKind::Import { binding, .. } => binding.local_def_id(),
1048+
}
1049+
}
1050+
10301051
fn defined_with(&self, modifiers: DefModifiers) -> bool {
10311052
self.modifiers.contains(modifiers)
10321053
}
@@ -1038,11 +1059,12 @@ impl<'a> NameBinding<'a> {
10381059
fn def_and_lp(&self) -> (Def, LastPrivate) {
10391060
let def = self.def().unwrap();
10401061
if let Def::Err = def { return (def, LastMod(AllPublic)) }
1041-
(def, LastMod(if self.is_public() { AllPublic } else { DependsOn(def.def_id()) }))
1062+
let lp = if self.is_public() { AllPublic } else { DependsOn(self.local_def_id().unwrap()) };
1063+
(def, LastMod(lp))
10421064
}
10431065

10441066
fn is_extern_crate(&self) -> bool {
1045-
self.module().map(|module| module.is_extern_crate).unwrap_or(false)
1067+
self.module().and_then(|module| module.extern_crate_did).is_some()
10461068
}
10471069

10481070
fn is_import(&self) -> bool {
@@ -1236,9 +1258,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12361258
self.arenas.name_bindings.alloc(name_binding)
12371259
}
12381260

1239-
fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def) -> Module<'a> {
1240-
let mut module = ModuleS::new(parent_link, Some(def), false, true);
1241-
module.is_extern_crate = true;
1261+
fn new_extern_crate_module(&self,
1262+
parent_link: ParentLink<'a>,
1263+
def: Def,
1264+
is_public: bool,
1265+
local_def: DefId)
1266+
-> Module<'a> {
1267+
let mut module = ModuleS::new(parent_link, Some(def), false, is_public);
1268+
module.extern_crate_did = Some(local_def);
12421269
self.arenas.modules.alloc(module)
12431270
}
12441271

@@ -1357,7 +1384,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13571384
// Keep track of the closest private module used
13581385
// when resolving this import chain.
13591386
if !binding.is_public() {
1360-
if let Some(did) = search_module.def_id() {
1387+
if let Some(did) = search_module.local_def_id() {
13611388
closest_private = LastMod(DependsOn(did));
13621389
}
13631390
}
@@ -1462,7 +1489,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14621489
Success(PrefixFound(ref containing_module, index)) => {
14631490
search_module = containing_module;
14641491
start_index = index;
1465-
last_private = LastMod(DependsOn(containing_module.def_id()
1492+
last_private = LastMod(DependsOn(containing_module.local_def_id()
14661493
.unwrap()));
14671494
}
14681495
}
@@ -3571,7 +3598,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
35713598

35723599
if !in_module_is_extern || name_binding.is_public() {
35733600
// add the module to the lookup
3574-
let is_extern = in_module_is_extern || module.is_extern_crate;
3601+
let is_extern = in_module_is_extern || name_binding.is_extern_crate();
35753602
worklist.push((module, path_segments, is_extern));
35763603
}
35773604
}

src/librustc_resolve/resolve_imports.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
394394
directive.is_public &&
395395
!name_binding.is_public() => {
396396
let msg = format!("`{}` is private, and cannot be reexported", source);
397-
let note_msg = format!("Consider marking `{}` as `pub` in the imported module",
397+
let note_msg = format!("consider marking `{}` as `pub` in the imported module",
398398
source);
399399
struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg)
400400
.span_note(directive.span, &note_msg)
@@ -403,12 +403,22 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
403403

404404
(_, &Success(name_binding)) if !name_binding.is_import() && directive.is_public => {
405405
if !name_binding.is_public() {
406-
let msg = format!("`{}` is private, and cannot be reexported", source);
407-
let note_msg =
408-
format!("Consider declaring type or module `{}` with `pub`", source);
409-
struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
410-
.span_note(directive.span, &note_msg)
411-
.emit();
406+
if name_binding.is_extern_crate() {
407+
let msg = format!("extern crate `{}` is private, and cannot be reexported \
408+
(error E0364), consider declaring with `pub`",
409+
source);
410+
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
411+
directive.id,
412+
directive.span,
413+
msg);
414+
} else {
415+
let msg = format!("`{}` is private, and cannot be reexported", source);
416+
let note_msg =
417+
format!("consider declaring type or module `{}` with `pub`", source);
418+
struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
419+
.span_note(directive.span, &note_msg)
420+
.emit();
421+
}
412422
} else if name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
413423
let msg = format!("variant `{}` is private, and cannot be reexported \
414424
(error E0364), consider declaring its enum as `pub`",
@@ -441,9 +451,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
441451
module_.decrement_outstanding_references_for(target, TypeNS);
442452

443453
let def_and_priv = |binding: &NameBinding| {
444-
let def = binding.def().unwrap();
445-
let last_private = if binding.is_public() { lp } else { DependsOn(def.def_id()) };
446-
(def, last_private)
454+
let last_private =
455+
if binding.is_public() { lp } else { DependsOn(binding.local_def_id().unwrap()) };
456+
(binding.def().unwrap(), last_private)
447457
};
448458
let value_def_and_priv = value_result.success().map(&def_and_priv);
449459
let type_def_and_priv = type_result.success().map(&def_and_priv);
@@ -493,7 +503,6 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
493503
build_reduced_graph::populate_module_if_necessary(self.resolver, target_module);
494504
target_module.for_each_child(|name, ns, binding| {
495505
if !binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { return }
496-
if binding.is_extern_crate() { return }
497506
self.define(module_, name, ns, directive.import(binding));
498507

499508
if ns == TypeNS && directive.is_public &&

src/librustc_trans/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ extern crate rustc;
4646
extern crate rustc_back;
4747
extern crate rustc_data_structures;
4848
extern crate rustc_front;
49-
extern crate rustc_llvm as llvm;
49+
pub extern crate rustc_llvm as llvm;
5050
extern crate rustc_mir;
5151
extern crate rustc_platform_intrinsics as intrinsics;
5252
extern crate serialize;

src/libstd/sys/unix/net.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use sys_common::net::{getsockopt, setsockopt};
2121
use time::Duration;
2222

2323
pub use sys::{cvt, cvt_r};
24-
pub use libc as netc;
24+
pub extern crate libc as netc;
2525

2626
pub type wrlen_t = size_t;
2727

src/libsyntax/parse/parser.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5487,13 +5487,6 @@ impl<'a> Parser<'a> {
54875487
try!(self.expect(&token::Semi));
54885488

54895489
let last_span = self.last_span;
5490-
5491-
if visibility == ast::Visibility::Public {
5492-
self.span_warn(mk_sp(lo, last_span.hi),
5493-
"`pub extern crate` does not work as expected and should not be used. \
5494-
Likely to become an error. Prefer `extern crate` and `pub use`.");
5495-
}
5496-
54975490
Ok(self.mk_item(lo,
54985491
last_span.hi,
54995492
ident,

src/test/auxiliary/privacy_reexport.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
pub extern crate core;
1112
pub use foo as bar;
1213

1314
pub mod foo {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(rustc_attrs)]
12+
#![allow(dead_code)]
13+
#![allow(unused_imports)]
14+
15+
mod foo {
16+
extern crate core;
17+
}
18+
19+
// Check that private crates can be used from outside their modules, albeit with warnings
20+
use foo::core; //~ WARN extern crate `core` is private
21+
//~^ WARN this was previously accepted by the compiler but is being phased out
22+
use foo::core::cell; //~ WARN extern crate `core` is private
23+
//~^ WARN this was previously accepted by the compiler but is being phased out
24+
25+
fn f() {
26+
foo::core::cell::Cell::new(0); //~ WARN extern crate `core` is private
27+
//~^ WARN this was previously accepted by the compiler but is being phased out
28+
29+
use foo::*;
30+
mod core {} // Check that private crates are not glob imported
31+
}
32+
33+
#[rustc_error]
34+
fn main() {} //~ ERROR compilation successful

src/test/compile-fail/no-extern-crate-in-glob-import.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/test/compile-fail/private-variant-reexport.rs renamed to src/test/compile-fail/private-variant-and-crate-reexport.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#![feature(rustc_attrs)]
1212
#![allow(dead_code)]
1313

14+
extern crate core;
15+
pub use core as reexported_core; //~ WARN extern crate `core` is private, and cannot be reexported
16+
//~^ WARNING hard error
17+
1418
mod m1 {
1519
pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported
1620
//~^ WARNING hard error

src/test/compile-fail/warn-pub-extern-crate.rs

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)