Warn that `#![feature(rust_2018_preview)]` is implied when the edition is set to Rust 2018.
cc @varkor @petrochenkov @joshtriplett
let mut features = Features::new();
let mut edition_enabled_features = FxHashMap();
- for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() {
+ for &edition in ALL_EDITIONS {
+ if edition <= crate_edition {
+ // The `crate_edition` implies its respective umbrella feature-gate
+ // (i.e. `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
+ edition_enabled_features.insert(Symbol::intern(edition.feature_name()), edition);
+ }
+ }
+
+ for &(name, .., f_edition, set) in ACTIVE_FEATURES {
if let Some(f_edition) = f_edition {
if f_edition <= crate_edition {
set(&mut features, DUMMY_SP);
}
}
+ // Process the edition umbrella feature-gates first, to ensure
+ // `edition_enabled_features` is completed before it's queried.
for attr in krate_attrs {
if !attr.check_name("feature") {
continue
let list = match attr.meta_item_list() {
Some(list) => list,
- None => {
- span_err!(span_handler, attr.span, E0555,
- "malformed feature attribute, expected #![feature(...)]");
- continue
- }
+ None => continue,
};
for mi in list {
let name = if let Some(word) = mi.word() {
word.name()
} else {
- span_err!(span_handler, mi.span, E0556,
- "malformed feature, expected just one word");
continue
};
if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
if *edition <= crate_edition {
- continue
+ continue;
}
- for &(name, .., f_edition, set) in ACTIVE_FEATURES.iter() {
+ for &(name, .., f_edition, set) in ACTIVE_FEATURES {
if let Some(f_edition) = f_edition {
if f_edition <= *edition {
// FIXME(Manishearth) there is currently no way to set
}
}
}
+ }
+ }
+ }
+
+ for attr in krate_attrs {
+ if !attr.check_name("feature") {
+ continue
+ }
+
+ let list = match attr.meta_item_list() {
+ Some(list) => list,
+ None => {
+ span_err!(span_handler, attr.span, E0555,
+ "malformed feature attribute, expected #![feature(...)]");
+ continue
+ }
+ };
+ for mi in list {
+ let name = if let Some(word) = mi.word() {
+ word.name()
+ } else {
+ span_err!(span_handler, mi.span, E0556,
+ "malformed feature, expected just one word");
continue
+ };
+
+ if let Some(edition) = edition_enabled_features.get(&name) {
+ struct_span_warn!(
+ span_handler,
+ mi.span,
+ E0705,
+ "the feature `{}` is included in the Rust {} edition",
+ name,
+ edition,
+ ).emit();
+ continue;
+ }
+
+ if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
+ // Handled in the separate loop above.
+ continue;
}
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
- if let Some(edition) = edition_enabled_features.get(&name) {
- struct_span_warn!(
- span_handler,
- mi.span,
- E0705,
- "the feature `{}` is included in the Rust {} edition",
- name,
- edition,
- ).emit();
- } else {
- set(&mut features, mi.span);
- features.declared_lang_features.push((name, mi.span, None));
- }
+ set(&mut features, mi.span);
+ features.declared_lang_features.push((name, mi.span, None));
continue
}
//
// This test focuses on non-error cases and making sure the correct number of repetitions happen.
-// compile-flags: --edition=2018
+// edition:2018
#![feature(macro_at_most_once_rep)]
// FIXME: once `--edition` is stable in rustdoc, remove that `compile-flags` directive
-#![feature(rust_2018_preview, async_await, futures_api)]
+#![feature(async_await, futures_api)]
// @has async_fn/struct.S.html
// @has - '//code' 'pub async fn f()'
// except according to those terms.
// aux-build:suggestions-not-always-applicable.rs
-// compile-flags: --edition 2015
+// edition:2015
// run-rustfix
// rustfix-only-machine-applicable
// compile-pass
// except according to those terms.
// aux-build:suggestions-not-always-applicable.rs
-// compile-flags: --edition 2015
+// edition:2015
// run-rustfix
// rustfix-only-machine-applicable
// compile-pass
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --edition 2018
+// edition:2018
#![deny(unused_extern_crates)]
#![feature(alloc, test, libc)]
// compile-pass
-#![feature(rust_2018_preview)]
#![feature(raw_identifiers)]
//~^ WARN the feature `raw_identifiers` is included in the Rust 2018 edition
+#![feature(rust_2018_preview)]
fn main() {
let foo = 0;
warning[E0705]: the feature `raw_identifiers` is included in the Rust 2018 edition
- --> $DIR/E0705.rs:14:12
+ --> $DIR/E0705.rs:13:12
|
LL | #![feature(raw_identifiers)]
| ^^^^^^^^^^^^^^^
// revisions: zflag edition
// [zflag]compile-flags: -Z borrowck=migrate
-// [edition]compile-flags: --edition 2018
+// [edition]edition:2018
#![feature(nll)]
// revisions: zflag edition
//[zflag]compile-flags: -Z borrowck=migrate
-//[edition]compile-flags: --edition 2018
+//[edition]edition:2018
//[zflag] run-pass
//[edition] run-pass
// revisions: ast zflags edition
//[zflags]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
-//[edition]compile-flags: --edition 2018
+//[edition]edition:2018
// run-pass
// except according to those terms.
// aux-build:edition-extern-crate-allowed.rs
-// compile-flags: --edition 2015
+// edition:2015
// compile-pass
#![warn(rust_2018_idioms)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:--edition 2018
// compile-pass
#![feature(rust_2018_preview)]
--- /dev/null
+// Copyright 2018 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.
+
+// edition:2018
+// compile-pass
+
+#![feature(rust_2018_preview)]
+//~^ WARN the feature `rust_2018_preview` is included in the Rust 2018 edition
+
+fn main() {}
--- /dev/null
+warning[E0705]: the feature `rust_2018_preview` is included in the Rust 2018 edition
+ --> $DIR/edition-feature-redundant.rs:14:12
+ |
+LL | #![feature(rust_2018_preview)]
+ | ^^^^^^^^^^^^^^^^^
+
// except according to those terms.
// run-rustfix
-// compile-flags: --edition 2018
+// edition:2018
#![allow(unused)]
#![deny(elided_lifetimes_in_paths)]
// except according to those terms.
// run-rustfix
-// compile-flags: --edition 2018
+// edition:2018
#![allow(unused)]
#![deny(elided_lifetimes_in_paths)]
// with the feature flag.
// gate-test-macro_at_most_once_rep
-// compile-flags: --edition=2015
+// edition:2015
#![feature(macro_at_most_once_rep)]
// Test behavior of `?` macro _kleene op_ under the 2015 edition. Namely, it doesn't exist.
-// compile-flags: --edition=2015
+// edition:2015
macro_rules! bar {
($(a)?) => {} //~ERROR expected `*` or `+`
// Test behavior of `?` macro _separator_ under the 2015 edition. Namely, `?` can be used as a
// separator, but you get a migration warning for the edition.
-// compile-flags: --edition=2015
+// edition:2015
// compile-pass
#![warn(rust_2018_compatibility)]
// Feature gate test for macro_at_most_once_rep under 2018 edition.
// gate-test-macro_at_most_once_rep
-// compile-flags: --edition=2018
+// edition:2018
macro_rules! foo {
($(a)?) => {}
// Tests that `?` is a Kleene op and not a macro separator in the 2018 edition.
-// compile-flags: --edition=2018
+// edition:2018
#![feature(macro_at_most_once_rep)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --edition 2018
+// edition:2018
// aux-build:removing-extern-crate.rs
// run-rustfix
// compile-pass
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --edition 2018
+// edition:2018
// aux-build:removing-extern-crate.rs
// run-rustfix
// compile-pass
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --edition 2015
+// edition:2015
#![deny(rust_2018_compatibility)]
// aux-build:edition-lint-paths.rs
// run-rustfix
-// compile-flags:--edition 2018
+// edition:2018
// The "normal case". Ideally we would remove the `extern crate` here,
// but we don't.
-#![feature(rust_2018_preview)]
#![deny(rust_2018_idioms)]
#![allow(dead_code)]
// aux-build:edition-lint-paths.rs
// run-rustfix
-// compile-flags:--edition 2018
+// edition:2018
// The "normal case". Ideally we would remove the `extern crate` here,
// but we don't.
-#![feature(rust_2018_preview)]
#![deny(rust_2018_idioms)]
#![allow(dead_code)]
error: unused extern crate
- --> $DIR/extern-crate-idiomatic-in-2018.rs:22:1
+ --> $DIR/extern-crate-idiomatic-in-2018.rs:21:1
|
LL | extern crate edition_lint_paths;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
|
note: lint level defined here
- --> $DIR/extern-crate-idiomatic-in-2018.rs:19:9
+ --> $DIR/extern-crate-idiomatic-in-2018.rs:18:9
|
LL | #![deny(rust_2018_idioms)]
| ^^^^^^^^^^^^^^^^
= note: #[deny(unused_extern_crates)] implied by #[deny(rust_2018_idioms)]
error: `extern crate` is not idiomatic in the new edition
- --> $DIR/extern-crate-idiomatic-in-2018.rs:25:1
+ --> $DIR/extern-crate-idiomatic-in-2018.rs:24:1
|
LL | extern crate edition_lint_paths as bar;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --edition 2018
+// edition:2018
// The local `use` suggestion should start with `crate::` (but the
// standard-library suggestions should not, obviously).