diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 45169a2f656..ee0ce32bfec 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -32,6 +32,9 @@ pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::crate) fn use_std(crate: &ast::crate) -> bool { !attr::attrs_contains_name(crate.node.attrs, "no_std") } +fn no_prelude(attrs: &[ast::attribute]) -> bool { + attr::attrs_contains_name(attrs, "no_implicit_prelude") +} fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate { fn spanned(x: T) -> codemap::spanned { @@ -63,7 +66,12 @@ fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate { view_items: vis, ../*bad*/copy crate.module }; - new_module = fld.fold_mod(&new_module); + + if !no_prelude(crate.attrs) { + // only add `use std::prelude::*;` if there wasn't a + // `#[no_implicit_prelude];` at the crate level. + new_module = fld.fold_mod(&new_module); + } // FIXME #2543: Bad copy. let new_crate = ast::crate_ { @@ -72,6 +80,16 @@ fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate { }; (new_crate, span) }, + fold_item: |item, fld| { + 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, fld) + } else { + Some(item) + } + }, fold_mod: |module, fld| { let n2 = sess.next_node_id(); diff --git a/src/test/compile-fail/no-implicit-prelude-nested.rs b/src/test/compile-fail/no-implicit-prelude-nested.rs new file mode 100644 index 00000000000..e215407ec87 --- /dev/null +++ b/src/test/compile-fail/no-implicit-prelude-nested.rs @@ -0,0 +1,68 @@ +// 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. + +// 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_implicit_prelude` stops working, then the `impl Add` will still +// fail with the same error message). + +#[no_implicit_prelude] +mod foo { + mod baz { + struct Test; + impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl ToStr for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait + + fn foo() { + print("foo"); //~ ERROR: unresolved name + println("bar"); //~ ERROR: unresolved name + } + } + + struct Test; + impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl ToStr for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait + + fn foo() { + print("foo"); //~ ERROR: unresolved name + println("bar"); //~ ERROR: unresolved name + } +} + +fn qux() { + #[no_implicit_prelude] + mod qux_inner { + struct Test; + impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl ToStr for Test {} //~ ERROR: attempt to implement a nonexistent trait + impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait + + fn foo() { + print("foo"); //~ ERROR: unresolved name + println("bar"); //~ ERROR: unresolved name + } + } +} + + +fn main() { + // these should work fine + print("foo"); + println("bar"); +} diff --git a/src/test/compile-fail/no-implicit-prelude.rs b/src/test/compile-fail/no-implicit-prelude.rs new file mode 100644 index 00000000000..ca4533a03c8 --- /dev/null +++ b/src/test/compile-fail/no-implicit-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. + +#[no_implicit_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_implicit_prelude` stops working, then the `impl Add` will still +// fail with the same error message). + +struct Test; +impl Add for Test {} //~ ERROR: attempt to implement a nonexistent trait +impl Clone for Test {} //~ ERROR: attempt to implement a nonexistent trait +impl Iterator for Test {} //~ ERROR: attempt to implement a nonexistent trait +impl ToStr for Test {} //~ ERROR: attempt to implement a nonexistent trait +impl Writer for Test {} //~ ERROR: attempt to implement a nonexistent trait + +fn main() { + print("foo"); //~ ERROR: unresolved name + println("bar"); //~ ERROR: unresolved name +}