From a23e4fc5116f6d7ec5e045533e89c0c14ac868e2 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 22 Feb 2016 14:05:01 +0100 Subject: [PATCH 01/15] Add crate_name in E0152 error display --- src/librustc/middle/lang_items.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index a22ad7a0707c2..6cbb90627eab5 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -184,10 +184,13 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { // Check for duplicates. match self.items.items[item_index] { Some(original_def_id) if original_def_id != item_def_id => { + let cstore = &self.session.cstore; span_err!(self.session, span, E0152, - "duplicate entry for `{}`", LanguageItems::item_name(item_index)); + "duplicate entry for `{}`, first definition found in `{}`", + LanguageItems::item_name(item_index), + cstore.crate_name(item_def_id.krate)); } - Some(_) | None => { + _ => { // OK. } } From dfe72fa4ce2c31be3ee941f6df216e3a463cf68a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 20 Feb 2016 22:53:29 +0100 Subject: [PATCH 02/15] Add test for E0152 error message improvement --- .../compile-fail/duplicate_entry_error.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/compile-fail/duplicate_entry_error.rs diff --git a/src/test/compile-fail/duplicate_entry_error.rs b/src/test/compile-fail/duplicate_entry_error.rs new file mode 100644 index 0000000000000..d39553a7267e0 --- /dev/null +++ b/src/test/compile-fail/duplicate_entry_error.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test for issue #31788 + +// error-pattern: duplicate entry for `panic_fmt`, first definition found in `std` + +#![feature(lang_items)] + +#[lang = "panic_fmt"] +fn panic_fmt() -> ! { + loop {} +} + +fn main() {} \ No newline at end of file From d4fda669def560eaa5445adee2ec3725a31848f5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 20 Feb 2016 18:19:32 -0800 Subject: [PATCH 03/15] mk: Specify armv6 for gcc on arm-unknown-linux-* Right now the compiler's we're using actually default to armv7/thumb2 I believe, so this should help push them back to what the arm-unknown-linux-* targets are for. This at least matches that clang does for the `arm-unknown-linux-gnueabihf` target which is to map it to an armv6 architecture. Closes #31787 --- mk/cfg/arm-unknown-linux-gnueabi.mk | 4 ++-- mk/cfg/arm-unknown-linux-gnueabihf.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mk/cfg/arm-unknown-linux-gnueabi.mk b/mk/cfg/arm-unknown-linux-gnueabi.mk index 9244cc43650fe..f66ad04eefe8e 100644 --- a/mk/cfg/arm-unknown-linux-gnueabi.mk +++ b/mk/cfg/arm-unknown-linux-gnueabi.mk @@ -8,8 +8,8 @@ CFG_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).so CFG_STATIC_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).a CFG_LIB_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.so CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM -CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS) -CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS) +CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv6 -marm +CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv6 -marm CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/arm-unknown-linux-gnueabihf.mk b/mk/cfg/arm-unknown-linux-gnueabihf.mk index 0bd661ea00db2..defe0dc3e70eb 100644 --- a/mk/cfg/arm-unknown-linux-gnueabihf.mk +++ b/mk/cfg/arm-unknown-linux-gnueabihf.mk @@ -8,8 +8,8 @@ CFG_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).so CFG_STATIC_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).a CFG_LIB_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.so CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.dylib.dSYM -CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabihf := -D__arm__ $(CFLAGS) -CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLAGS) +CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabihf := -D__arm__ $(CFLAGS) -march=armv6 -marm +CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLAGS) -march=armv6 -marm CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list= From b49ce1a599dffd2496a2f2f2bebbd8c4e1947cab Mon Sep 17 00:00:00 2001 From: Kevin Stock Date: Mon, 22 Feb 2016 22:37:02 -0500 Subject: [PATCH 04/15] Fix warn(unused_mut) in example --- src/doc/book/patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/patterns.md b/src/doc/book/patterns.md index 6fd7f4cd4755a..7325d448962cf 100644 --- a/src/doc/book/patterns.md +++ b/src/doc/book/patterns.md @@ -303,7 +303,7 @@ struct Person { } let name = "Steve".to_string(); -let mut x: Option = Some(Person { name: Some(name) }); +let x: Option = Some(Person { name: Some(name) }); match x { Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a), _ => {} From 60ce31a00c533b5fe54a50893c30712d3b677f06 Mon Sep 17 00:00:00 2001 From: tormol Date: Tue, 23 Feb 2016 05:55:49 +0100 Subject: [PATCH 05/15] Correct char.encode_utf16() documentation The "A buffer that's too small" example was calling encode_utf8(). --- src/librustc_unicode/char.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index a489b4991f4b6..20f4687f2f429 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -476,7 +476,7 @@ impl char { /// /// let mut b = [0; 0]; /// - /// let result = 'ß'.encode_utf8(&mut b); + /// let result = 'ß'.encode_utf16(&mut b); /// /// assert_eq!(result, None); /// ``` From b38a856e3851cd9557a5d79f524cc2e69c5664fc Mon Sep 17 00:00:00 2001 From: mitaa Date: Tue, 23 Feb 2016 09:52:44 +0100 Subject: [PATCH 06/15] Don't show associated consts from trait impls --- src/librustdoc/html/render.rs | 10 ++++++++++ src/test/rustdoc/issue-31808.rs | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/rustdoc/issue-31808.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 692d230446cda..a30c087bd8b85 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -243,6 +243,7 @@ pub struct Cache { stack: Vec, parent_stack: Vec, + parent_is_trait_impl: bool, search_index: Vec, privmod: bool, remove_priv: bool, @@ -487,6 +488,7 @@ pub fn run(mut krate: clean::Crate, stack: Vec::new(), parent_stack: Vec::new(), search_index: Vec::new(), + parent_is_trait_impl: false, extern_locations: HashMap::new(), primitive_locations: HashMap::new(), remove_priv: cx.passes.contains("strip-private"), @@ -995,6 +997,10 @@ impl DocFolder for Cache { // Index this method for searching later on if let Some(ref s) = item.name { let (parent, is_method) = match item.inner { + clean::AssociatedConstItem(..) if self.parent_is_trait_impl => { + // skip associated consts in trait impls + ((None, None), false) + } clean::AssociatedTypeItem(..) | clean::AssociatedConstItem(..) | clean::TyMethodItem(..) | @@ -1115,12 +1121,15 @@ impl DocFolder for Cache { } // Maintain the parent stack + let orig_parent_is_trait_impl = self.parent_is_trait_impl; let parent_pushed = match item.inner { clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => { self.parent_stack.push(item.def_id); + self.parent_is_trait_impl = false; true } clean::ImplItem(ref i) => { + self.parent_is_trait_impl = i.trait_.is_some(); match i.for_ { clean::ResolvedPath{ did, .. } => { self.parent_stack.push(did); @@ -1201,6 +1210,7 @@ impl DocFolder for Cache { if pushed { self.stack.pop().unwrap(); } if parent_pushed { self.parent_stack.pop().unwrap(); } self.privmod = orig_privmod; + self.parent_is_trait_impl = orig_parent_is_trait_impl; return ret; } } diff --git a/src/test/rustdoc/issue-31808.rs b/src/test/rustdoc/issue-31808.rs new file mode 100644 index 0000000000000..46be8229d7c65 --- /dev/null +++ b/src/test/rustdoc/issue-31808.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts, associated_types)] + +// Test that associated item impls on primitive types don't crash rustdoc + +pub trait Foo { + const BAR: usize; + type BAZ; +} + +impl Foo for () { + const BAR: usize = 0; + type BAZ = usize; +} From f5df7e086516ba6398f2a1538c1c6d3193846f55 Mon Sep 17 00:00:00 2001 From: mitaa Date: Tue, 23 Feb 2016 10:24:53 +0100 Subject: [PATCH 07/15] Show associated types in inherent impls --- src/librustdoc/html/render.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a30c087bd8b85..8a061e3a528e7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -997,8 +997,9 @@ impl DocFolder for Cache { // Index this method for searching later on if let Some(ref s) = item.name { let (parent, is_method) = match item.inner { - clean::AssociatedConstItem(..) if self.parent_is_trait_impl => { - // skip associated consts in trait impls + clean::AssociatedConstItem(..) | + clean::TypedefItem(_, true) if self.parent_is_trait_impl => { + // skip associated items in trait impls ((None, None), false) } clean::AssociatedTypeItem(..) | @@ -1032,10 +1033,6 @@ impl DocFolder for Cache { ((Some(*last), path), true) } } - clean::TypedefItem(_, true) => { - // skip associated types in impls - ((None, None), false) - } _ => ((None, Some(&*self.stack)), false) }; let hidden_field = match item.inner { From 3358fb11da258007d26cc27364455c610088d630 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 2 Feb 2016 20:21:24 +0000 Subject: [PATCH 08/15] Fix the visibility of extern crate declarations and stop warning on pub extern crate --- src/librustc_resolve/build_reduced_graph.rs | 12 ++++- src/librustc_resolve/lib.rs | 47 +++++++++++++++---- src/librustc_resolve/resolve_imports.rs | 10 ++-- src/libsyntax/parse/parser.rs | 7 --- src/test/auxiliary/privacy_reexport.rs | 1 + .../compile-fail/extern-crate-visibility.rs | 23 +++++++++ .../no-extern-crate-in-glob-import.rs | 22 --------- .../compile-fail/warn-pub-extern-crate.rs | 16 ------- src/test/run-pass/privacy-reexport.rs | 3 ++ 9 files changed, 80 insertions(+), 61 deletions(-) create mode 100644 src/test/compile-fail/extern-crate-visibility.rs delete mode 100644 src/test/compile-fail/no-extern-crate-in-glob-import.rs delete mode 100644 src/test/compile-fail/warn-pub-extern-crate.rs diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a25968174fd4e..385fae46cbae8 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -293,9 +293,19 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { self.external_exports.insert(def_id); let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(def_id); - let external_module = self.new_extern_crate_module(parent_link, def); + let local_def_id = self.ast_map.local_def_id(item.id); + let external_module = + self.new_extern_crate_module(parent_link, def, is_public, local_def_id); self.define(parent, name, TypeNS, (external_module, sp)); + if is_public { + let export = Export { name: name, def_id: def_id }; + if let Some(def_id) = parent.def_id() { + let node_id = self.resolver.ast_map.as_local_node_id(def_id).unwrap(); + self.export_map.entry(node_id).or_insert(Vec::new()).push(export); + } + } + self.build_reduced_graph_for_external_crate(external_module); } parent diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 11c51522b6763..3e2837f023ddb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -806,7 +806,10 @@ pub struct ModuleS<'a> { parent_link: ParentLink<'a>, def: Option, is_public: bool, - is_extern_crate: bool, + + // If the module is an extern crate, `def` is root of the external crate and `extern_crate_did` + // is the DefId of the local `extern crate` item (otherwise, `extern_crate_did` is None). + extern_crate_did: Option, resolutions: RefCell>>, unresolved_imports: RefCell>, @@ -853,7 +856,7 @@ impl<'a> ModuleS<'a> { parent_link: parent_link, def: def, is_public: is_public, - is_extern_crate: false, + extern_crate_did: None, resolutions: RefCell::new(HashMap::new()), unresolved_imports: RefCell::new(Vec::new()), module_children: RefCell::new(NodeMap()), @@ -917,6 +920,16 @@ impl<'a> ModuleS<'a> { self.def.as_ref().map(Def::def_id) } + // This returns the DefId of the crate local item that controls this module's visibility. + // It is only used to compute `LastPrivate` data, and it differs from `def_id` only for extern + // crates, whose `def_id` is the external crate's root, not the local `extern crate` item. + fn local_def_id(&self) -> Option { + match self.extern_crate_did { + Some(def_id) => Some(def_id), + None => self.def_id(), + } + } + fn is_normal(&self) -> bool { match self.def { Some(Def::Mod(_)) | Some(Def::ForeignMod(_)) => true, @@ -1027,6 +1040,14 @@ impl<'a> NameBinding<'a> { } } + fn local_def_id(&self) -> Option { + match self.kind { + NameBindingKind::Def(def) => Some(def.def_id()), + NameBindingKind::Module(ref module) => module.local_def_id(), + NameBindingKind::Import { binding, .. } => binding.local_def_id(), + } + } + fn defined_with(&self, modifiers: DefModifiers) -> bool { self.modifiers.contains(modifiers) } @@ -1038,11 +1059,12 @@ impl<'a> NameBinding<'a> { fn def_and_lp(&self) -> (Def, LastPrivate) { let def = self.def().unwrap(); if let Def::Err = def { return (def, LastMod(AllPublic)) } - (def, LastMod(if self.is_public() { AllPublic } else { DependsOn(def.def_id()) })) + let lp = if self.is_public() { AllPublic } else { DependsOn(self.local_def_id().unwrap()) }; + (def, LastMod(lp)) } fn is_extern_crate(&self) -> bool { - self.module().map(|module| module.is_extern_crate).unwrap_or(false) + self.module().and_then(|module| module.extern_crate_did).is_some() } fn is_import(&self) -> bool { @@ -1236,9 +1258,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.arenas.name_bindings.alloc(name_binding) } - fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), false, true); - module.is_extern_crate = true; + fn new_extern_crate_module(&self, + parent_link: ParentLink<'a>, + def: Def, + is_public: bool, + local_def: DefId) + -> Module<'a> { + let mut module = ModuleS::new(parent_link, Some(def), false, is_public); + module.extern_crate_did = Some(local_def); self.arenas.modules.alloc(module) } @@ -1357,7 +1384,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Keep track of the closest private module used // when resolving this import chain. if !binding.is_public() { - if let Some(did) = search_module.def_id() { + if let Some(did) = search_module.local_def_id() { closest_private = LastMod(DependsOn(did)); } } @@ -1462,7 +1489,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Success(PrefixFound(ref containing_module, index)) => { search_module = containing_module; start_index = index; - last_private = LastMod(DependsOn(containing_module.def_id() + last_private = LastMod(DependsOn(containing_module.local_def_id() .unwrap())); } } @@ -3571,7 +3598,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !in_module_is_extern || name_binding.is_public() { // add the module to the lookup - let is_extern = in_module_is_extern || module.is_extern_crate; + let is_extern = in_module_is_extern || name_binding.is_extern_crate(); worklist.push((module, path_segments, is_extern)); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 9c6e51c647c78..4cefffce777f7 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -402,7 +402,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } (_, &Success(name_binding)) if !name_binding.is_import() && directive.is_public => { - if !name_binding.is_public() { + // Disallow reexporting private items, excepting extern crates. + if !name_binding.is_public() && !name_binding.is_extern_crate() { let msg = format!("`{}` is private, and cannot be reexported", source); let note_msg = format!("Consider declaring type or module `{}` with `pub`", source); @@ -441,9 +442,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { module_.decrement_outstanding_references_for(target, TypeNS); let def_and_priv = |binding: &NameBinding| { - let def = binding.def().unwrap(); - let last_private = if binding.is_public() { lp } else { DependsOn(def.def_id()) }; - (def, last_private) + let last_private = + if binding.is_public() { lp } else { DependsOn(binding.local_def_id().unwrap()) }; + (binding.def().unwrap(), last_private) }; let value_def_and_priv = value_result.success().map(&def_and_priv); let type_def_and_priv = type_result.success().map(&def_and_priv); @@ -493,7 +494,6 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { build_reduced_graph::populate_module_if_necessary(self.resolver, target_module); target_module.for_each_child(|name, ns, binding| { if !binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { return } - if binding.is_extern_crate() { return } self.define(module_, name, ns, directive.import(binding)); if ns == TypeNS && directive.is_public && diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a5f998b318e34..999ae036ebbd3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5487,13 +5487,6 @@ impl<'a> Parser<'a> { try!(self.expect(&token::Semi)); let last_span = self.last_span; - - if visibility == ast::Visibility::Public { - self.span_warn(mk_sp(lo, last_span.hi), - "`pub extern crate` does not work as expected and should not be used. \ - Likely to become an error. Prefer `extern crate` and `pub use`."); - } - Ok(self.mk_item(lo, last_span.hi, ident, diff --git a/src/test/auxiliary/privacy_reexport.rs b/src/test/auxiliary/privacy_reexport.rs index e60dbb290b079..fd97f210a5514 100644 --- a/src/test/auxiliary/privacy_reexport.rs +++ b/src/test/auxiliary/privacy_reexport.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +pub extern crate core; pub use foo as bar; pub mod foo { diff --git a/src/test/compile-fail/extern-crate-visibility.rs b/src/test/compile-fail/extern-crate-visibility.rs new file mode 100644 index 0000000000000..95eeb60c1ea7e --- /dev/null +++ b/src/test/compile-fail/extern-crate-visibility.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod foo { + extern crate core; + pub use self::core as reexported_core; // Check that private extern crates can be reexported +} + +// Check that private crates cannot be used from outside their modules +use foo::core; //~ ERROR module `core` is inaccessible +use foo::core::cell; //~ ERROR + +fn main() { + use foo::*; + mod core {} // Check that private crates are not glob imported +} diff --git a/src/test/compile-fail/no-extern-crate-in-glob-import.rs b/src/test/compile-fail/no-extern-crate-in-glob-import.rs deleted file mode 100644 index 75882c5e98129..0000000000000 --- a/src/test/compile-fail/no-extern-crate-in-glob-import.rs +++ /dev/null @@ -1,22 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Check that extern crate declarations are excluded from glob imports. - -#![feature(core)] -extern crate core; - -mod T { - pub use super::*; -} - -fn main() { - use T::core; //~ ERROR unresolved import `T::core` -} diff --git a/src/test/compile-fail/warn-pub-extern-crate.rs b/src/test/compile-fail/warn-pub-extern-crate.rs deleted file mode 100644 index de3cc27c49bd2..0000000000000 --- a/src/test/compile-fail/warn-pub-extern-crate.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_attrs)] - -pub extern crate core; //~WARN `pub extern crate` does not work - -#[rustc_error] -fn main() {} //~ ERROR: compilation successful diff --git a/src/test/run-pass/privacy-reexport.rs b/src/test/run-pass/privacy-reexport.rs index d9d107d900b6a..15c977afe2a6c 100644 --- a/src/test/run-pass/privacy-reexport.rs +++ b/src/test/run-pass/privacy-reexport.rs @@ -15,5 +15,8 @@ extern crate privacy_reexport; pub fn main() { + // Check that public extern crates are visible to outside crates + privacy_reexport::core::cell::Cell::new(0); + privacy_reexport::bar::frob(); } From f8d6dcf46ec646a41d0dc222764cc0ed026ceb03 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 2 Feb 2016 09:39:59 +0000 Subject: [PATCH 09/15] Warn when reexporting a private extern crate --- src/librustc/lib.rs | 4 +-- src/librustc_resolve/resolve_imports.rs | 25 +++++++++++++------ src/librustc_trans/lib.rs | 2 +- src/libstd/sys/unix/net.rs | 2 +- ... => private-variant-and-crate-reexport.rs} | 4 +++ 5 files changed, 24 insertions(+), 13 deletions(-) rename src/test/compile-fail/{private-variant-reexport.rs => private-variant-and-crate-reexport.rs} (88%) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 53fd867e7fd48..bd256d19b6725 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -51,7 +51,7 @@ extern crate getopts; extern crate graphviz; extern crate libc; extern crate rbml; -extern crate rustc_llvm; +pub extern crate rustc_llvm as llvm; extern crate rustc_back; extern crate rustc_front; extern crate rustc_data_structures; @@ -66,8 +66,6 @@ extern crate serialize as rustc_serialize; // used by deriving #[cfg(test)] extern crate test; -pub use rustc_llvm as llvm; - #[macro_use] mod macros; diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4cefffce777f7..4776c83b94cf1 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -402,14 +402,23 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } (_, &Success(name_binding)) if !name_binding.is_import() && directive.is_public => { - // Disallow reexporting private items, excepting extern crates. - if !name_binding.is_public() && !name_binding.is_extern_crate() { - let msg = format!("`{}` is private, and cannot be reexported", source); - let note_msg = - format!("Consider declaring type or module `{}` with `pub`", source); - struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg) - .span_note(directive.span, ¬e_msg) - .emit(); + if !name_binding.is_public() { + if name_binding.is_extern_crate() { + let msg = format!("extern crate `{}` is private, and cannot be reexported \ + (error E0364), consider declaring with `pub`", + source); + self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, + directive.id, + directive.span, + msg); + } else { + let msg = format!("`{}` is private, and cannot be reexported", source); + let note_msg = + format!("Consider declaring type or module `{}` with `pub`", source); + struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); + } } else if name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) { let msg = format!("variant `{}` is private, and cannot be reexported \ (error E0364), consider declaring its enum as `pub`", diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 27d6dbae28a67..6f596b15b9214 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -46,7 +46,7 @@ extern crate rustc; extern crate rustc_back; extern crate rustc_data_structures; extern crate rustc_front; -extern crate rustc_llvm as llvm; +pub extern crate rustc_llvm as llvm; extern crate rustc_mir; extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 507cc0f4ea461..16c369674f0a2 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -21,7 +21,7 @@ use sys_common::net::{getsockopt, setsockopt}; use time::Duration; pub use sys::{cvt, cvt_r}; -pub use libc as netc; +pub extern crate libc as netc; pub type wrlen_t = size_t; diff --git a/src/test/compile-fail/private-variant-reexport.rs b/src/test/compile-fail/private-variant-and-crate-reexport.rs similarity index 88% rename from src/test/compile-fail/private-variant-reexport.rs rename to src/test/compile-fail/private-variant-and-crate-reexport.rs index 06f08dc13c6b4..5811d82681e6b 100644 --- a/src/test/compile-fail/private-variant-reexport.rs +++ b/src/test/compile-fail/private-variant-and-crate-reexport.rs @@ -11,6 +11,10 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +extern crate core; +pub use core as reexported_core; //~ WARN extern crate `core` is private, and cannot be reexported +//~^ WARNING hard error + mod m1 { pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported //~^ WARNING hard error From 5172745da761842a40a625c804f5e0360586996d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 12 Feb 2016 06:42:44 +0000 Subject: [PATCH 10/15] Warn instead of error when using an inaccessable extern crate --- src/librustc/lint/builtin.rs | 7 +++++++ src/librustc_lint/lib.rs | 4 ++++ src/librustc_privacy/lib.rs | 16 ++++++++++++++ .../compile-fail/extern-crate-visibility.rs | 21 ++++++++++++++----- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 99fea59e28d94..4bb69a2688a41 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -124,6 +124,12 @@ declare_lint! { "detect private items in public interfaces not caught by the old implementation" } +declare_lint! { + pub INACCESSIBLE_EXTERN_CRATE, + Warn, + "use of inaccessible extern crate erroneously allowed" +} + declare_lint! { pub INVALID_TYPE_PARAM_DEFAULT, Warn, @@ -167,6 +173,7 @@ impl LintPass for HardwiredLints { TRIVIAL_CASTS, TRIVIAL_NUMERIC_CASTS, PRIVATE_IN_PUBLIC, + INACCESSIBLE_EXTERN_CRATE, INVALID_TYPE_PARAM_DEFAULT, MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, CONST_ERR, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 6868b4f2ab768..1cf0339c086e5 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -158,6 +158,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(PRIVATE_IN_PUBLIC), reference: "the explanation for E0446 (`--explain E0446`)", }, + FutureIncompatibleInfo { + id: LintId::of(INACCESSIBLE_EXTERN_CRATE), + reference: "PR 31362 ", + }, FutureIncompatibleInfo { id: LintId::of(INVALID_TYPE_PARAM_DEFAULT), reference: "PR 30742 ", diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index f0786b9b1fadd..8908dac7a36dd 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -743,6 +743,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { source_did: Option, msg: &str) -> CheckResult { + use rustc_front::hir::Item_::ItemExternCrate; debug!("ensure_public(span={:?}, to_check={:?}, source_did={:?}, msg={:?})", span, to_check, source_did, msg); let def_privacy = self.def_privacy(to_check); @@ -763,6 +764,21 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // be local.) let def_id = source_did.unwrap_or(to_check); let node_id = self.tcx.map.as_local_node_id(def_id); + + // Warn when using a inaccessible extern crate. + if let Some(node_id) = self.tcx.map.as_local_node_id(to_check) { + match self.tcx.map.get(node_id) { + ast_map::Node::NodeItem(&hir::Item { node: ItemExternCrate(_), name, .. }) => { + self.tcx.sess.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, + node_id, + span, + format!("extern crate `{}` is private", name)); + return None; + } + _ => {} + } + } + let (err_span, err_msg) = if Some(id) == node_id { return Some((span, format!("{} is private", msg), None)); } else { diff --git a/src/test/compile-fail/extern-crate-visibility.rs b/src/test/compile-fail/extern-crate-visibility.rs index 95eeb60c1ea7e..56a41a15ab3c0 100644 --- a/src/test/compile-fail/extern-crate-visibility.rs +++ b/src/test/compile-fail/extern-crate-visibility.rs @@ -8,16 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_imports)] + mod foo { extern crate core; - pub use self::core as reexported_core; // Check that private extern crates can be reexported } -// Check that private crates cannot be used from outside their modules -use foo::core; //~ ERROR module `core` is inaccessible -use foo::core::cell; //~ ERROR +// Check that private crates can be used from outside their modules, albeit with warnings +use foo::core; //~ WARN extern crate `core` is private +//~^ WARN this was previously accepted by the compiler but is being phased out +use foo::core::cell; //~ WARN extern crate `core` is private +//~^ WARN this was previously accepted by the compiler but is being phased out + +fn f() { + foo::core::cell::Cell::new(0); //~ WARN extern crate `core` is private + //~^ WARN this was previously accepted by the compiler but is being phased out -fn main() { use foo::*; mod core {} // Check that private crates are not glob imported } + +#[rustc_error] +fn main() {} //~ ERROR compilation successful From d34c6eeed49acb227bbd07db9d321319cec5dd56 Mon Sep 17 00:00:00 2001 From: tormol Date: Wed, 24 Feb 2016 06:27:00 +0100 Subject: [PATCH 11/15] Use a character that requires two `u16`s in the examples for `char.encode_utf16()` --- src/librustc_unicode/char.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 20f4687f2f429..115002867555d 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -457,16 +457,16 @@ impl char { /// /// # Examples /// - /// In both of these examples, 'ß' takes one `u16` to encode. + /// In both of these examples, '𝕊' takes two `u16`s to encode. /// /// ``` /// #![feature(unicode)] /// - /// let mut b = [0; 1]; + /// let mut b = [0; 2]; /// - /// let result = 'ß'.encode_utf16(&mut b); + /// let result = '𝕊'.encode_utf16(&mut b); /// - /// assert_eq!(result, Some(1)); + /// assert_eq!(result, Some(2)); /// ``` /// /// A buffer that's too small: @@ -474,9 +474,9 @@ impl char { /// ``` /// #![feature(unicode)] /// - /// let mut b = [0; 0]; + /// let mut b = [0; 1]; /// - /// let result = 'ß'.encode_utf16(&mut b); + /// let result = '𝕊'.encode_utf16(&mut b); /// /// assert_eq!(result, None); /// ``` From 7ad7065c35e6ec0881f917e2fea3615f1dfeaed3 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 24 Feb 2016 08:47:45 +0000 Subject: [PATCH 12/15] Uncapitalize note messages --- src/librustc_resolve/resolve_imports.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4776c83b94cf1..c068ff258b0e7 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -394,7 +394,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { directive.is_public && !name_binding.is_public() => { let msg = format!("`{}` is private, and cannot be reexported", source); - let note_msg = format!("Consider marking `{}` as `pub` in the imported module", + let note_msg = format!("consider marking `{}` as `pub` in the imported module", source); struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg) .span_note(directive.span, ¬e_msg) @@ -414,7 +414,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { } else { let msg = format!("`{}` is private, and cannot be reexported", source); let note_msg = - format!("Consider declaring type or module `{}` with `pub`", source); + format!("consider declaring type or module `{}` with `pub`", source); struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg) .span_note(directive.span, ¬e_msg) .emit(); From 27ca2507defe13c5c989a9aa64d138645a7db65e Mon Sep 17 00:00:00 2001 From: mitaa Date: Wed, 24 Feb 2016 19:40:16 +0100 Subject: [PATCH 13/15] Allow creation of src-links for device files --- src/librustdoc/html/render.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 692d230446cda..267220891b98b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1489,9 +1489,11 @@ impl<'a> Item<'a> { true, |component| { path.push(component.to_string()); }); + // If the span points into an external macro the // source-file will be bogus, i.e `` - if Path::new(&self.item.source.filename).is_file() { + let filename = &self.item.source.filename; + if !(filename.starts_with("<") && filename.ends_with("macros>")) { Some(format!("{root}src/{krate}/{path}.html#{href}", root = self.cx.root_path, krate = self.cx.layout.krate, From cf76fcf30d1efefd01bba0ed9b81cd867262346f Mon Sep 17 00:00:00 2001 From: mitaa Date: Tue, 23 Feb 2016 07:52:43 +0100 Subject: [PATCH 14/15] Fix source-links for files with absolute-paths `clean_srcpath` tries to make the source-path relative to `src_root`, but this didn't work since `src_root` itself wasn't absolute. --- src/librustdoc/clean/mod.rs | 9 ++++++++- src/librustdoc/html/render.rs | 15 ++++++++------- src/test/rustdoc/issue-26995.rs | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 src/test/rustdoc/issue-26995.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7072f1b498bb9..1ff88f1d12758 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -48,6 +48,7 @@ use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; use std::u32; +use std::env::current_dir; use core::DocContext; use doctree; @@ -201,7 +202,13 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { } let src = match cx.input { - Input::File(ref path) => path.clone(), + Input::File(ref path) => { + if path.is_absolute() { + path.clone() + } else { + current_dir().unwrap().join(path) + } + }, Input::Str(_) => PathBuf::new() // FIXME: this is wrong }; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 267220891b98b..a7c796dd2f5cd 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -46,7 +46,7 @@ use std::io::prelude::*; use std::io::{self, BufWriter, BufReader}; use std::iter::repeat; use std::mem; -use std::path::{PathBuf, Path}; +use std::path::{PathBuf, Path, Component}; use std::str; use std::sync::Arc; @@ -810,16 +810,17 @@ fn clean_srcpath(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) wh // make it relative, if possible let p = p.strip_prefix(src_root).unwrap_or(p); - let mut iter = p.iter().map(|x| x.to_str().unwrap()).peekable(); + let mut iter = p.components().peekable(); + while let Some(c) = iter.next() { if !keep_filename && iter.peek().is_none() { break; } - if ".." == c { - f("up"); - } else { - f(c) + match c { + Component::ParentDir => f("up"), + Component::Normal(c) => f(c.to_str().unwrap()), + _ => continue, } } } @@ -871,7 +872,7 @@ impl<'a> DocFolder for SourceCollector<'a> { // entire crate. The other option is maintaining this mapping on a // per-file basis, but that's probably not worth it... self.cx - .include_sources = match self.emit_source(&item.source .filename) { + .include_sources = match self.emit_source(&item.source.filename) { Ok(()) => true, Err(e) => { println!("warning: source code was requested to be rendered, \ diff --git a/src/test/rustdoc/issue-26995.rs b/src/test/rustdoc/issue-26995.rs new file mode 100644 index 0000000000000..bfb440a18392e --- /dev/null +++ b/src/test/rustdoc/issue-26995.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-windows +// compile-flags: --no-defaults + +// @has src/issue_26995/dev/null.html +// @has issue_26995/null/index.html '//a/@href' '../../src/issue_26995/dev/null.html' +#[path="/dev/null"] +pub mod null; From 128283347086ff307b39c8c848d0831c6dcf576a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 19 Feb 2016 22:03:54 -0800 Subject: [PATCH 15/15] rustc: Refactor how unstable flags are handled This commit adds support for *truly* unstable options in the compiler, as well as adding warnings for the start of the deprecation path of unstable-but-not-really options. Specifically, the following behavior is now in place for handling unstable options: * As before, an unconditional error is emitted if an unstable option is passed and the `-Z unstable-options` flag is not present. Note that passing another `-Z` flag does not require passing `-Z unstable-options` as well. * New flags added to the compiler will be in the `Unstable` category as opposed to the `UnstableButNotReally` category which means they will unconditionally emit an error when used on stable. * All current flags are in a category where they will emit warnings when used that the option will soon be a hard error. Also as before, it is intended that `-Z` is akin to `#![feature]` in a crate where it is required to unlock unstable functionality. A nightly compiler which is used without any `-Z` flags should only be exercising stable behavior. --- src/librustc/session/config.rs | 181 +++++++++++++++++++++------------ src/librustc_driver/lib.rs | 150 +++++++++++++++++---------- 2 files changed, 215 insertions(+), 116 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index f835613cfcbb9..ea08bf021fbba 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -749,24 +749,20 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { } } -/// Returns the "short" subset of the stable rustc command line options. -pub fn short_optgroups() -> Vec { - rustc_short_optgroups().into_iter() - .filter(|g|g.is_stable()) - .map(|g|g.opt_group) - .collect() -} - -/// Returns all of the stable rustc command line options. -pub fn optgroups() -> Vec { - rustc_optgroups().into_iter() - .filter(|g|g.is_stable()) - .map(|g|g.opt_group) - .collect() -} - #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum OptionStability { Stable, Unstable } +pub enum OptionStability { + Stable, + + // FIXME: historically there were some options which were either `-Z` or + // required the `-Z unstable-options` flag, which were all intended + // to be unstable. Unfortunately we didn't actually gate usage of + // these options on the stable compiler, so we still allow them there + // today. There are some warnings printed out about this in the + // driver. + UnstableButNotReally, + + Unstable, +} #[derive(Clone, PartialEq, Eq)] pub struct RustcOptGroup { @@ -783,9 +779,17 @@ impl RustcOptGroup { RustcOptGroup { opt_group: g, stability: OptionStability::Stable } } + #[allow(dead_code)] // currently we have no "truly unstable" options fn unstable(g: getopts::OptGroup) -> RustcOptGroup { RustcOptGroup { opt_group: g, stability: OptionStability::Unstable } } + + fn unstable_bnr(g: getopts::OptGroup) -> RustcOptGroup { + RustcOptGroup { + opt_group: g, + stability: OptionStability::UnstableButNotReally, + } + } } // The `opt` local module holds wrappers around the `getopts` API that @@ -807,24 +811,57 @@ mod opt { fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) } fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) } + fn unstable_bnr(g: getopts::OptGroup) -> R { RustcOptGroup::unstable_bnr(g) } - // FIXME (pnkfelix): We default to stable since the current set of - // options is defacto stable. However, it would be good to revise the - // code so that a stable option is the thing that takes extra effort - // to encode. - - pub fn opt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optopt(a, b, c, d)) } - pub fn multi(a: S, b: S, c: S, d: S) -> R { stable(getopts::optmulti(a, b, c, d)) } - pub fn flag(a: S, b: S, c: S) -> R { stable(getopts::optflag(a, b, c)) } - pub fn flagopt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optflagopt(a, b, c, d)) } - pub fn flagmulti(a: S, b: S, c: S) -> R { stable(getopts::optflagmulti(a, b, c)) } + pub fn opt_s(a: S, b: S, c: S, d: S) -> R { + stable(getopts::optopt(a, b, c, d)) + } + pub fn multi_s(a: S, b: S, c: S, d: S) -> R { + stable(getopts::optmulti(a, b, c, d)) + } + pub fn flag_s(a: S, b: S, c: S) -> R { + stable(getopts::optflag(a, b, c)) + } + pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R { + stable(getopts::optflagopt(a, b, c, d)) + } + pub fn flagmulti_s(a: S, b: S, c: S) -> R { + stable(getopts::optflagmulti(a, b, c)) + } + pub fn opt(a: S, b: S, c: S, d: S) -> R { + unstable(getopts::optopt(a, b, c, d)) + } + pub fn multi(a: S, b: S, c: S, d: S) -> R { + unstable(getopts::optmulti(a, b, c, d)) + } + pub fn flag(a: S, b: S, c: S) -> R { + unstable(getopts::optflag(a, b, c)) + } + pub fn flagopt(a: S, b: S, c: S, d: S) -> R { + unstable(getopts::optflagopt(a, b, c, d)) + } + pub fn flagmulti(a: S, b: S, c: S) -> R { + unstable(getopts::optflagmulti(a, b, c)) + } - pub fn opt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optopt(a, b, c, d)) } - pub fn multi_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optmulti(a, b, c, d)) } - pub fn flag_u(a: S, b: S, c: S) -> R { unstable(getopts::optflag(a, b, c)) } - pub fn flagopt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optflagopt(a, b, c, d)) } - pub fn flagmulti_u(a: S, b: S, c: S) -> R { unstable(getopts::optflagmulti(a, b, c)) } + // Do not use these functions for any new options added to the compiler, all + // new options should use the `*_u` variants above to be truly unstable. + pub fn opt_ubnr(a: S, b: S, c: S, d: S) -> R { + unstable_bnr(getopts::optopt(a, b, c, d)) + } + pub fn multi_ubnr(a: S, b: S, c: S, d: S) -> R { + unstable_bnr(getopts::optmulti(a, b, c, d)) + } + pub fn flag_ubnr(a: S, b: S, c: S) -> R { + unstable_bnr(getopts::optflag(a, b, c)) + } + pub fn flagopt_ubnr(a: S, b: S, c: S, d: S) -> R { + unstable_bnr(getopts::optflagopt(a, b, c, d)) + } + pub fn flagmulti_ubnr(a: S, b: S, c: S) -> R { + unstable_bnr(getopts::optflagmulti(a, b, c)) + } } /// Returns the "short" subset of the rustc command line options, @@ -832,44 +869,44 @@ mod opt { /// part of the stable long-term interface for rustc. pub fn rustc_short_optgroups() -> Vec { vec![ - opt::flag("h", "help", "Display this message"), - opt::multi("", "cfg", "Configure the compilation environment", "SPEC"), - opt::multi("L", "", "Add a directory to the library search path", + opt::flag_s("h", "help", "Display this message"), + opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"), + opt::multi_s("L", "", "Add a directory to the library search path", "[KIND=]PATH"), - opt::multi("l", "", "Link the generated crate(s) to the specified native + opt::multi_s("l", "", "Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of, static, dylib, or framework. If omitted, dylib is assumed.", "[KIND=]NAME"), - opt::multi("", "crate-type", "Comma separated list of types of crates + opt::multi_s("", "crate-type", "Comma separated list of types of crates for the compiler to emit", "[bin|lib|rlib|dylib|staticlib]"), - opt::opt("", "crate-name", "Specify the name of the crate being built", + opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"), - opt::multi("", "emit", "Comma separated list of types of output for \ + opt::multi_s("", "emit", "Comma separated list of types of output for \ the compiler to emit", "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"), - opt::multi("", "print", "Comma separated list of compiler information to \ + opt::multi_s("", "print", "Comma separated list of compiler information to \ print on stdout", "[crate-name|file-names|sysroot|target-list]"), - opt::flagmulti("g", "", "Equivalent to -C debuginfo=2"), - opt::flagmulti("O", "", "Equivalent to -C opt-level=2"), - opt::opt("o", "", "Write output to ", "FILENAME"), - opt::opt("", "out-dir", "Write output to compiler-chosen filename \ + opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), + opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), + opt::opt_s("o", "", "Write output to ", "FILENAME"), + opt::opt_s("", "out-dir", "Write output to compiler-chosen filename \ in ", "DIR"), - opt::opt("", "explain", "Provide a detailed explanation of an error \ + opt::opt_s("", "explain", "Provide a detailed explanation of an error \ message", "OPT"), - opt::flag("", "test", "Build a test harness"), - opt::opt("", "target", "Target triple for which the code is compiled", "TARGET"), - opt::multi("W", "warn", "Set lint warnings", "OPT"), - opt::multi("A", "allow", "Set lint allowed", "OPT"), - opt::multi("D", "deny", "Set lint denied", "OPT"), - opt::multi("F", "forbid", "Set lint forbidden", "OPT"), - opt::multi("", "cap-lints", "Set the most restrictive lint level. \ + opt::flag_s("", "test", "Build a test harness"), + opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"), + opt::multi_s("W", "warn", "Set lint warnings", "OPT"), + opt::multi_s("A", "allow", "Set lint allowed", "OPT"), + opt::multi_s("D", "deny", "Set lint denied", "OPT"), + opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"), + opt::multi_s("", "cap-lints", "Set the most restrictive lint level. \ More restrictive lints are capped at this \ level", "LEVEL"), - opt::multi("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), - opt::flag("V", "version", "Print version info and exit"), - opt::flag("v", "verbose", "Use verbose output"), + opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), + opt::flag_s("V", "version", "Print version info and exit"), + opt::flag_s("v", "verbose", "Use verbose output"), ] } @@ -879,24 +916,26 @@ pub fn rustc_short_optgroups() -> Vec { pub fn rustc_optgroups() -> Vec { let mut opts = rustc_short_optgroups(); opts.extend_from_slice(&[ - opt::multi("", "extern", "Specify where an external rust library is \ + opt::multi_s("", "extern", "Specify where an external rust library is \ located", "NAME=PATH"), - opt::opt("", "sysroot", "Override the system root", "PATH"), - opt::multi("Z", "", "Set internal debugging options", "FLAG"), - opt::opt_u("", "error-format", "How errors and other messages are produced", "human|json"), - opt::opt("", "color", "Configure coloring of output: + opt::opt_s("", "sysroot", "Override the system root", "PATH"), + opt::multi_ubnr("Z", "", "Set internal debugging options", "FLAG"), + opt::opt_ubnr("", "error-format", + "How errors and other messages are produced", + "human|json"), + opt::opt_s("", "color", "Configure coloring of output: auto = colorize, if output goes to a tty (default); always = always colorize output; never = never colorize output", "auto|always|never"), - opt::flagopt_u("", "pretty", + opt::flagopt_ubnr("", "pretty", "Pretty-print the input instead of compiling; valid types are: `normal` (un-annotated source), `expanded` (crates expanded), or `expanded,identified` (fully parenthesized, AST nodes with IDs).", "TYPE"), - opt::flagopt_u("", "unpretty", + opt::flagopt_ubnr("", "unpretty", "Present the input source, unstable (and less-pretty) variants; valid types are any of the types for `--pretty`, as well as: `flowgraph=` (graphviz formatted flowgraph for node), @@ -904,6 +943,14 @@ pub fn rustc_optgroups() -> Vec { `hir` (the HIR), `hir,identified`, or `hir,typed` (HIR with types for each node).", "TYPE"), + + // new options here should **not** use the `_ubnr` functions, all new + // unstable options should use the short variants to indicate that they + // are truly unstable. All `_ubnr` flags are just that way because they + // were so historically. + // + // You may also wish to keep this comment at the bottom of this list to + // ensure that others see it. ]); opts } @@ -1242,15 +1289,21 @@ impl fmt::Display for CrateType { #[cfg(test)] mod tests { use middle::cstore::DummyCrateStore; - use session::config::{build_configuration, optgroups, build_session_options}; + use session::config::{build_configuration, build_session_options}; use session::build_session; use std::rc::Rc; - use getopts::getopts; + use getopts::{getopts, OptGroup}; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::diagnostics; + fn optgroups() -> Vec { + super::rustc_optgroups().into_iter() + .map(|a| a.opt_group) + .collect() + } + // When the user supplies --test we should implicitly supply --cfg test #[test] fn test_switch_implies_cfg_test() { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e77663091106b..d0f86cfcb46ba 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -65,6 +65,7 @@ use rustc_trans::back::link; use rustc_trans::save; use rustc::session::{config, Session, build_session, CompileResult}; use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; +use rustc::session::config::{get_unstable_features_setting, OptionStability}; use rustc::middle::cstore::CrateStore; use rustc::lint::Lint; use rustc::lint; @@ -85,7 +86,7 @@ use std::str; use std::sync::{Arc, Mutex}; use std::thread; -use rustc::session::early_error; +use rustc::session::{early_error, early_warn}; use syntax::ast; use syntax::parse; @@ -93,6 +94,7 @@ use syntax::errors; use syntax::errors::emitter::Emitter; use syntax::diagnostics; use syntax::parse::token; +use syntax::feature_gate::UnstableFeatures; #[cfg(test)] pub mod test; @@ -819,8 +821,31 @@ fn print_flag_list(cmdline_opt: &str, } /// Process command line options. Emits messages as appropriate. If compilation -/// should continue, returns a getopts::Matches object parsed from args, otherwise -/// returns None. +/// should continue, returns a getopts::Matches object parsed from args, +/// otherwise returns None. +/// +/// The compiler's handling of options is a little complication as it ties into +/// our stability story, and it's even *more* complicated by historical +/// accidents. The current intention of each compiler option is to have one of +/// three modes: +/// +/// 1. An option is stable and can be used everywhere. +/// 2. An option is unstable, but was historically allowed on the stable +/// channel. +/// 3. An option is unstable, and can only be used on nightly. +/// +/// Like unstable library and language features, however, unstable options have +/// always required a form of "opt in" to indicate that you're using them. This +/// provides the easy ability to scan a code base to check to see if anything +/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag. +/// +/// All options behind `-Z` are considered unstable by default. Other top-level +/// options can also be considered unstable, and they were unlocked through the +/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of +/// instability in both cases, though. +/// +/// So with all that in mind, the comments below have some more detail about the +/// contortions done here to get things to work out correctly. pub fn handle_options(mut args: Vec) -> Option { // Throw away the first argument, the name of the binary let _binary = args.remove(0); @@ -832,62 +857,83 @@ pub fn handle_options(mut args: Vec) -> Option { return None; } - fn allows_unstable_options(matches: &getopts::Matches) -> bool { - let r = matches.opt_strs("Z"); - r.iter().any(|x| *x == "unstable-options") - } + // Parse with *all* options defined in the compiler, we don't worry about + // option stability here we just want to parse as much as possible. + let all_groups: Vec = config::rustc_optgroups() + .into_iter() + .map(|x| x.opt_group) + .collect(); + let matches = match getopts::getopts(&args[..], &all_groups) { + Ok(m) => m, + Err(f) => early_error(ErrorOutputType::default(), &f.to_string()), + }; - fn parse_all_options(args: &Vec) -> getopts::Matches { - let all_groups: Vec = config::rustc_optgroups() - .into_iter() - .map(|x| x.opt_group) - .collect(); - match getopts::getopts(&args[..], &all_groups) { - Ok(m) => { - if !allows_unstable_options(&m) { - // If -Z unstable-options was not specified, verify that - // no unstable options were present. - for opt in config::rustc_optgroups().into_iter().filter(|x| !x.is_stable()) { - let opt_name = if !opt.opt_group.long_name.is_empty() { - &opt.opt_group.long_name - } else { - &opt.opt_group.short_name - }; - if m.opt_present(opt_name) { - early_error(ErrorOutputType::default(), - &format!("use of unstable option '{}' requires -Z \ - unstable-options", - opt_name)); - } - } - } - m - } - Err(f) => early_error(ErrorOutputType::default(), &f.to_string()), + // For all options we just parsed, we check a few aspects: + // + // * If the option is stable, we're all good + // * If the option wasn't passed, we're all good + // * If `-Z unstable-options` wasn't passed (and we're not a -Z option + // ourselves), then we require the `-Z unstable-options` flag to unlock + // this option that was passed. + // * If we're a nightly compiler, then unstable options are now unlocked, so + // we're good to go. + // * Otherwise, if we're a truly unstable option then we generate an error + // (unstable option being used on stable) + // * If we're a historically stable-but-should-be-unstable option then we + // emit a warning that we're going to turn this into an error soon. + let has_z_unstable_options = matches.opt_strs("Z") + .iter() + .any(|x| *x == "unstable-options"); + let really_allows_unstable_options = match get_unstable_features_setting() { + UnstableFeatures::Disallow => false, + _ => true, + }; + for opt in config::rustc_optgroups() { + if opt.stability == OptionStability::Stable { + continue } - } - - // As a speed optimization, first try to parse the command-line using just - // the stable options. - let matches = match getopts::getopts(&args[..], &config::optgroups()) { - Ok(ref m) if allows_unstable_options(m) => { - // If -Z unstable-options was specified, redo parsing with the - // unstable options to ensure that unstable options are defined - // in the returned getopts::Matches. - parse_all_options(&args) + let opt_name = if !opt.opt_group.long_name.is_empty() { + &opt.opt_group.long_name + } else { + &opt.opt_group.short_name + }; + if !matches.opt_present(opt_name) { + continue } - Ok(m) => m, - Err(_) => { - // redo option parsing, including unstable options this time, - // in anticipation that the mishandled option was one of the - // unstable ones. - parse_all_options(&args) + if opt_name != "Z" && !has_z_unstable_options { + let msg = format!("the `-Z unstable-options` flag must also be \ + passed to enable the flag `{}`", opt_name); + early_error(ErrorOutputType::default(), &msg); } - }; + if really_allows_unstable_options { + continue + } + match opt.stability { + OptionStability::Unstable => { + let msg = format!("the option `{}` is only accepted on the \ + nightly compiler", opt_name); + early_error(ErrorOutputType::default(), &msg); + } + OptionStability::UnstableButNotReally => { + let msg = format!("the option `{}` is is unstable and should \ + only be used on the nightly compiler, but \ + it is currently accepted for backwards \ + compatibility; this will soon change, \ + see issue #31847 for more details", + opt_name); + early_warn(ErrorOutputType::default(), &msg); + } + OptionStability::Stable => {} + } + } if matches.opt_present("h") || matches.opt_present("help") { + // Only show unstable options in --help if we *really* accept unstable + // options, which catches the case where we got `-Z unstable-options` on + // the stable channel of Rust which was accidentally allowed + // historically. usage(matches.opt_present("verbose"), - allows_unstable_options(&matches)); + has_z_unstable_options && really_allows_unstable_options); return None; }