Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consistent no_prelude attribute #32025

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, 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)

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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);
}
Expand Down
62 changes: 38 additions & 24 deletions src/libsyntax/std_inject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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,
Expand All @@ -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<ast::Item>) -> SmallVector<P<ast::Item>> {
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,
Expand Down Expand Up @@ -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<ast::Item>) -> SmallVector<P<ast::Item>> {
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)
}
}
3 changes: 2 additions & 1 deletion src/test/compile-fail/associated-types-issue-20346.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/import-shadow-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/import-shadow-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/import-shadow-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/import-shadow-4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/import-shadow-5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/import-shadow-6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/test/compile-fail/import-shadow-7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/test/compile-fail/no-implicit-prelude-nested.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
// fail with the same error message).

#[no_implicit_prelude]
//~^ WARNING: deprecated
//~^^ WARNING: deprecated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come there are two warnings emitted here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature gate visitor is run twice, once before cfg expansion and once after. I could try and find some way to avoid the double up, but the existing simd attribute deprecation warning does the same.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm ok, we probably want to figure out whether we're deprecating or not before going to great lengths to figure this out, and it's probably fine either way.

mod foo {
mod baz {
struct Test;
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/test/compile-fail/no-implicit-prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/test/compile-fail/no-prelude-feature-gate.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![no_prelude] //~ ERROR: experimental feature
//~^ HELP: feature(no_prelude)
67 changes: 67 additions & 0 deletions src/test/compile-fail/no-prelude-nested.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(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<Test> 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)
}
29 changes: 29 additions & 0 deletions src/test/compile-fail/no-prelude.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(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
}
3 changes: 2 additions & 1 deletion src/test/compile-fail/tag-that-dare-not-speak-its-name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

// Issue #876

#![no_implicit_prelude]
#![feature(no_prelude)]
#![no_prelude]
use std::vec::Vec;

fn last<T>(v: Vec<&T> ) -> std::option::Option<T> {
Expand Down
4 changes: 2 additions & 2 deletions src/test/run-pass/associated-types-impl-redirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
3 changes: 2 additions & 1 deletion src/test/run-pass/issue-21363.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

// pretty-expanded FIXME #23616

#![no_implicit_prelude]
#![feature(no_prelude)]
#![no_prelude]

trait Iterator {
type Item;
Expand Down