diff --git a/src/doc/reference.md b/src/doc/reference.md index 4c5fd31b96ed1..c7385588d1b1e 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1885,8 +1885,7 @@ type int8_t = i8; ### Module-only attributes -- `no_implicit_prelude` - disable injecting `use std::prelude::*` in this - module. +- `no_prelude` - disable injecting `use std::prelude::*` in this module. - `path` - specifies the file to load the module from. `#[path="foo.rs"] mod bar;` is equivalent to `mod bar { /* contents of foo.rs */ }`. The path is taken relative to the directory that the current module is in. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fbaf28332c42c..0f095c2256551 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -251,6 +251,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // impl specialization (RFC 1210) ("specialization", "1.7.0", Some(31844), Active), + + // Allows using #![no_prelude] + ("no_prelude", "1.9.0", Some(20561), Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -297,6 +300,9 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("should_panic", Normal, Ungated), ("ignore", Normal, Ungated), ("no_implicit_prelude", Normal, Ungated), + ("no_prelude", Normal, Gated("no_prelude", + "the `#[no_prelude]` attribute is an \ + experimental feature")), ("reexport_test_harness_main", Normal, Ungated), ("link_args", Normal, Ungated), ("macro_escape", Normal, Ungated), @@ -852,6 +858,11 @@ impl<'a> PostExpansionVisitor<'a> { impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { + if &*attr.name() == "no_implicit_prelude" { + self.context.span_handler.span_warn(attr.span, + "the `#[no_implicit_prelude]` attribute is \ + deprecated, use `#[no_prelude]` instead"); + } if !self.context.cm.span_allows_unstable(attr.span) { self.context.check_attribute(attr, false); } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 9049b21d8b4bb..49b03f9f6fe01 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -59,6 +59,7 @@ pub fn maybe_inject_prelude(sess: &ParseSess, krate: ast::Crate) -> ast::Crate { let mut fold = PreludeInjector { span: ignored_span(sess, DUMMY_SP), crate_identifier: token::str_to_ident(name), + inject_prelude: true, }; fold.fold_crate(krate) } @@ -72,10 +73,14 @@ pub fn no_std(krate: &ast::Crate) -> bool { attr::contains_name(&krate.attrs, "no_std") || no_core(krate) } -fn no_prelude(attrs: &[ast::Attribute]) -> bool { +fn no_prelude_deep(attrs: &[ast::Attribute]) -> bool { attr::contains_name(attrs, "no_implicit_prelude") } +fn no_prelude(attrs: &[ast::Attribute]) -> bool { + attr::contains_name(attrs, "no_prelude") +} + struct CrateInjector { item_name: ast::Ident, crate_name: ast::Name, @@ -101,31 +106,11 @@ impl fold::Folder for CrateInjector { struct PreludeInjector { span: Span, crate_identifier: ast::Ident, + inject_prelude: bool, } -impl fold::Folder for PreludeInjector { - fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { - // only add `use std::prelude::*;` if there wasn't a - // `#![no_implicit_prelude]` at the crate level. - // fold_mod() will insert glob path. - if !no_prelude(&krate.attrs) { - krate.module = self.fold_mod(krate.module); - } - krate - } - - fn fold_item(&mut self, item: P) -> SmallVector> { - if !no_prelude(&item.attrs) { - // only recur if there wasn't `#![no_implicit_prelude]` - // on this item, i.e. this means that the prelude is not - // implicitly imported though the whole subtree - fold::noop_fold_item(item, self) - } else { - SmallVector::one(item) - } - } - - fn fold_mod(&mut self, mut mod_: ast::Mod) -> ast::Mod { +impl PreludeInjector { + fn inject_prelude(&self, mod_: &mut ast::Mod) { let prelude_path = ast::Path { span: self.span, global: false, @@ -165,7 +150,36 @@ impl fold::Folder for PreludeInjector { vis: ast::Visibility::Inherited, span: self.span, })); + } +} + +impl fold::Folder for PreludeInjector { + fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { + if !no_prelude_deep(&krate.attrs) { + self.inject_prelude = !no_prelude(&krate.attrs); + krate.module = self.fold_mod(krate.module); + } + krate + } + + fn fold_item(&mut self, item: P) -> SmallVector> { + if no_prelude_deep(&item.attrs) { + // don't recur if there was `#![no_implicit_prelude]` + // on this item, i.e. this means that the prelude is not + // implicitly imported though the whole subtree + SmallVector::one(item) + } else { + // don't include prelude if there was `#![no_prelude]` + // on this item, but do recur to sub-modules + self.inject_prelude = !no_prelude(&item.attrs); + fold::noop_fold_item(item, self) + } + } + fn fold_mod(&mut self, mut mod_: ast::Mod) -> ast::Mod { + if self.inject_prelude { + self.inject_prelude(&mut mod_); + } fold::noop_fold_mod(mod_, self) } } diff --git a/src/test/compile-fail/associated-types-issue-20346.rs b/src/test/compile-fail/associated-types-issue-20346.rs index a00aa8364bde2..7d93ab4e42720 100644 --- a/src/test/compile-fail/associated-types-issue-20346.rs +++ b/src/test/compile-fail/associated-types-issue-20346.rs @@ -11,7 +11,8 @@ // Test that we reliably check the value of the associated type. #![crate_type = "lib"] -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use std::option::Option::{self, None, Some}; use std::vec::Vec; diff --git a/src/test/compile-fail/import-shadow-1.rs b/src/test/compile-fail/import-shadow-1.rs index 503fa4eca527b..5fae4d2107061 100644 --- a/src/test/compile-fail/import-shadow-1.rs +++ b/src/test/compile-fail/import-shadow-1.rs @@ -10,7 +10,8 @@ // Test that import shadowing using globs causes errors -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use foo::*; use bar::*; //~ERROR a type named `Baz` has already been imported in this module diff --git a/src/test/compile-fail/import-shadow-2.rs b/src/test/compile-fail/import-shadow-2.rs index 0c107cf27f592..0984b8f084a40 100644 --- a/src/test/compile-fail/import-shadow-2.rs +++ b/src/test/compile-fail/import-shadow-2.rs @@ -10,7 +10,8 @@ // Test that import shadowing using globs causes errors -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use foo::*; use foo::*; //~ERROR a type named `Baz` has already been imported in this module diff --git a/src/test/compile-fail/import-shadow-3.rs b/src/test/compile-fail/import-shadow-3.rs index bf90973c2857e..e4a189d3644bc 100644 --- a/src/test/compile-fail/import-shadow-3.rs +++ b/src/test/compile-fail/import-shadow-3.rs @@ -10,7 +10,8 @@ // Test that import shadowing using globs causes errors -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use foo::Baz; use bar::*; //~ERROR a type named `Baz` has already been imported in this module diff --git a/src/test/compile-fail/import-shadow-4.rs b/src/test/compile-fail/import-shadow-4.rs index f21fdaae47ba0..1427377cd68f1 100644 --- a/src/test/compile-fail/import-shadow-4.rs +++ b/src/test/compile-fail/import-shadow-4.rs @@ -10,7 +10,8 @@ // Test that import shadowing using globs causes errors -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use foo::*; use bar::Baz; //~ERROR a type named `Baz` has already been imported in this module diff --git a/src/test/compile-fail/import-shadow-5.rs b/src/test/compile-fail/import-shadow-5.rs index dc300bc7baa77..09653a87d6097 100644 --- a/src/test/compile-fail/import-shadow-5.rs +++ b/src/test/compile-fail/import-shadow-5.rs @@ -10,7 +10,8 @@ // Test that import shadowing using globs causes errors -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use foo::Baz; use bar::Baz; //~ERROR a type named `Baz` has already been imported in this module diff --git a/src/test/compile-fail/import-shadow-6.rs b/src/test/compile-fail/import-shadow-6.rs index fa3b75c70f0b6..2a494ee723b50 100644 --- a/src/test/compile-fail/import-shadow-6.rs +++ b/src/test/compile-fail/import-shadow-6.rs @@ -10,7 +10,8 @@ // Test that import shadowing using globs causes errors -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use qux::*; use foo::*; //~ERROR a type named `Baz` has already been imported in this module diff --git a/src/test/compile-fail/import-shadow-7.rs b/src/test/compile-fail/import-shadow-7.rs index 34aba15b39228..48c4ace8ba3d0 100644 --- a/src/test/compile-fail/import-shadow-7.rs +++ b/src/test/compile-fail/import-shadow-7.rs @@ -10,7 +10,8 @@ // Test that import shadowing using globs causes errors -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use foo::*; use qux::*; //~ERROR a type named `Baz` has already been imported in this module diff --git a/src/test/compile-fail/no-implicit-prelude-nested.rs b/src/test/compile-fail/no-implicit-prelude-nested.rs index af1046bcd5d97..62e91b9b93d01 100644 --- a/src/test/compile-fail/no-implicit-prelude-nested.rs +++ b/src/test/compile-fail/no-implicit-prelude-nested.rs @@ -15,6 +15,8 @@ // fail with the same error message). #[no_implicit_prelude] +//~^ WARNING: deprecated +//~^^ WARNING: deprecated mod foo { mod baz { struct Test; @@ -43,6 +45,8 @@ mod foo { fn qux() { #[no_implicit_prelude] + //~^ WARNING: deprecated + //~^^ WARNING: deprecated mod qux_inner { struct Test; impl Add for Test {} //~ ERROR: not in scope diff --git a/src/test/compile-fail/no-implicit-prelude.rs b/src/test/compile-fail/no-implicit-prelude.rs index 4693fd14e7de7..7ecfad231af10 100644 --- a/src/test/compile-fail/no-implicit-prelude.rs +++ b/src/test/compile-fail/no-implicit-prelude.rs @@ -9,6 +9,8 @@ // except according to those terms. #![no_implicit_prelude] +//~^ WARN deprecated +//~^^ WARN deprecated // Test that things from the prelude aren't in scope. Use many of them // so that renaming some things won't magically make this test fail diff --git a/src/test/compile-fail/no-prelude-feature-gate.rs b/src/test/compile-fail/no-prelude-feature-gate.rs new file mode 100644 index 0000000000000..f9b142bd1bb9a --- /dev/null +++ b/src/test/compile-fail/no-prelude-feature-gate.rs @@ -0,0 +1,12 @@ +// 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. + +#![no_prelude] //~ ERROR: experimental feature +//~^ HELP: feature(no_prelude) diff --git a/src/test/compile-fail/no-prelude-nested.rs b/src/test/compile-fail/no-prelude-nested.rs new file mode 100644 index 0000000000000..1f1e7917b8fbe --- /dev/null +++ b/src/test/compile-fail/no-prelude-nested.rs @@ -0,0 +1,67 @@ +// Copyright 2013 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(no_prelude)] + +// Test that things from the prelude aren't in scope. Use many of them +// so that renaming some things won't magically make this test fail +// for the wrong reason (e.g. if `Add` changes to `Addition`, and +// `no_prelude` stops working, then the `impl Add` will still +// fail with the same error message). +// +// Unlike `no_implicit_prelude`, `no_prelude` doesn't cascade into nested +// modules, this makes the impl in foo::baz work. + +#[no_prelude] +mod foo { + mod baz { + struct Test; + impl From for Test { fn from(t: Test) { Test }} + impl Clone for Test { fn clone(&self) { Test } } + impl Eq for Test {} + + fn foo() { + drop(2) + } + } + + struct Test; + impl From for Test {} //~ ERROR: not in scope + impl Clone for Test {} //~ ERROR: not in scope + impl Iterator for Test {} //~ ERROR: not in scope + impl ToString for Test {} //~ ERROR: not in scope + impl Eq for Test {} //~ ERROR: not in scope + + fn foo() { + drop(2) //~ ERROR: unresolved name + } +} + +fn qux() { + #[no_prelude] + mod qux_inner { + struct Test; + impl From for Test {} //~ ERROR: not in scope + impl Clone for Test {} //~ ERROR: not in scope + impl Iterator for Test {} //~ ERROR: not in scope + impl ToString for Test {} //~ ERROR: not in scope + impl Eq for Test {} //~ ERROR: not in scope + + fn foo() { + drop(2) //~ ERROR: unresolved name + } + } +} + + +fn main() { + // these should work fine + drop(2) +} diff --git a/src/test/compile-fail/no-prelude.rs b/src/test/compile-fail/no-prelude.rs new file mode 100644 index 0000000000000..285f7185af817 --- /dev/null +++ b/src/test/compile-fail/no-prelude.rs @@ -0,0 +1,29 @@ +// Copyright 2013 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(no_prelude)] +#![no_prelude] + +// Test that things from the prelude aren't in scope. Use many of them +// so that renaming some things won't magically make this test fail +// for the wrong reason (e.g. if `Add` changes to `Addition`, and +// `no_prelude` stops working, then the `impl Add` will still +// fail with the same error message). + +struct Test; +impl Add for Test {} //~ ERROR: not in scope +impl Clone for Test {} //~ ERROR: not in scope +impl Iterator for Test {} //~ ERROR: not in scope +impl ToString for Test {} //~ ERROR: not in scope +impl Writer for Test {} //~ ERROR: not in scope + +fn main() { + drop(2) //~ ERROR: unresolved name +} diff --git a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs index 660c1fa9a88d8..f93cf93b3aeb5 100644 --- a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs +++ b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs @@ -10,7 +10,8 @@ // Issue #876 -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] use std::vec::Vec; fn last(v: Vec<&T> ) -> std::option::Option { diff --git a/src/test/run-pass/associated-types-impl-redirect.rs b/src/test/run-pass/associated-types-impl-redirect.rs index 4082580a123ff..91256f6f87031 100644 --- a/src/test/run-pass/associated-types-impl-redirect.rs +++ b/src/test/run-pass/associated-types-impl-redirect.rs @@ -14,8 +14,8 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items, unboxed_closures)] -#![no_implicit_prelude] +#![feature(no_prelude, lang_items, unboxed_closures)] +#![no_prelude] use std::marker::Sized; use std::option::Option::{None, Some, self}; diff --git a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs index 082ad53d5593d..0d020e0a2e25d 100644 --- a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs +++ b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs @@ -14,8 +14,8 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items, unboxed_closures)] -#![no_implicit_prelude] +#![feature(no_prelude, lang_items, unboxed_closures)] +#![no_prelude] use std::marker::Sized; use std::option::Option::{None, Some, self}; diff --git a/src/test/run-pass/issue-21363.rs b/src/test/run-pass/issue-21363.rs index 608c60d03b3e7..3918c7abea08b 100644 --- a/src/test/run-pass/issue-21363.rs +++ b/src/test/run-pass/issue-21363.rs @@ -10,7 +10,8 @@ // pretty-expanded FIXME #23616 -#![no_implicit_prelude] +#![feature(no_prelude)] +#![no_prelude] trait Iterator { type Item;