Skip to content

Commit

Permalink
Rollup merge of #118802 - ehuss:remove-edition-preview, r=TaKO8Ki
Browse files Browse the repository at this point in the history
Remove edition umbrella features.

In the 2018 edition, there was an "umbrella" feature `#[feature(rust_2018_preview)]` which was used to enable several other features at once. This umbrella mechanism was not used in the 2021 edition and likely will not be used in 2024 either. During 2018 users reported that setting the feature was awkward, especially since they already needed to opt-in via the edition mechanism.

This PR removes this mechanism because I believe it will not be used (and will clean up and simplify the code). I believe that there are better ways to handle features and editions. In short:

- For highly experimental features, that may or may not be involved in an edition, they can implement regular feature gates like `tcx.features().my_feature`.
- For experimental features that *might* be involved in an edition, they should implement gates with `tcx.features().my_feature && span.at_least_rust_20xx()`. This requires the user to still specify `#![feature(my_feature)]`, to avoid disrupting testing of other edition features which are ready and have been accepted within the edition.
- For experimental features that have graduated to definitely be part of an edition, they should implement gates with `tcx.features().my_feature || span.at_least_rust_20xx()`, or just remove the feature check altogether and just check `span.at_least_rust_20xx()`.
- For relatively simple changes, they can skip the whole feature gating thing and just check `span.at_least_rust_20xx()`, and rely on the instability of the edition itself (which requires `-Zunstable-options`) to gate it.

I am working on documenting all of this in the rustc-dev-guide.
  • Loading branch information
GuillaumeGomez authored Dec 11, 2023
2 parents 8b1ba11 + f481596 commit 54d6bde
Show file tree
Hide file tree
Showing 49 changed files with 471 additions and 652 deletions.
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0705.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#### Note: this error code is no longer emitted by the compiler.

A `#![feature]` attribute was declared for a feature that is stable in the
current edition, but not in all editions.

Erroneous code example:

```rust2018,compile_fail,E0705
```compile_fail
#![feature(rust_2018_preview)]
#![feature(test_2018_feature)] // error: the feature
// `test_2018_feature` is
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_expand/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ expand_explain_doc_comment_outer =
expand_expr_repeat_no_syntax_vars =
attempted to repeat an expression containing no syntax variables matched as repeating at this depth
expand_feature_included_in_edition =
the feature `{$feature}` is included in the Rust {$edition} edition
expand_feature_not_allowed =
the feature `{$name}` is not in the list of allowed features
Expand Down
74 changes: 2 additions & 72 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Conditional compilation stripping.

use crate::errors::{
FeatureIncludedInEdition, FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg,
MalformedFeatureAttribute, MalformedFeatureAttributeHelp, RemoveExprNotSupported,
FeatureNotAllowed, FeatureRemoved, FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute,
MalformedFeatureAttributeHelp, RemoveExprNotSupported,
};
use rustc_ast::ptr::P;
use rustc_ast::token::{Delimiter, Token, TokenKind};
Expand All @@ -12,13 +12,11 @@ use rustc_ast::NodeId;
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
use rustc_attr as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_data_structures::fx::FxHashSet;
use rustc_feature::Features;
use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES};
use rustc_parse::validate_attr;
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::edition::ALL_EDITIONS;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use thin_vec::ThinVec;
Expand Down Expand Up @@ -47,42 +45,6 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -

let mut features = Features::default();

// The edition from `--edition`.
let crate_edition = sess.edition();

// The maximum of (a) the edition from `--edition` and (b) any edition
// umbrella feature-gates declared in the code.
// - E.g. if `crate_edition` is 2015 but `rust_2018_preview` is present,
// `feature_edition` is 2018
let mut features_edition = crate_edition;
for attr in krate_attrs {
for mi in feature_list(attr) {
if mi.is_word() {
let name = mi.name_or_empty();
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
if let Some(edition) = edition
&& edition > features_edition
{
features_edition = edition;
}
}
}
}

// Enable edition-dependent features based on `features_edition`.
// - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher
let mut edition_enabled_features = FxHashSet::default();
for f in UNSTABLE_FEATURES {
if let Some(edition) = f.feature.edition
&& edition <= features_edition
{
// FIXME(Manishearth) there is currently no way to set lib features by
// edition.
edition_enabled_features.insert(f.feature.name);
(f.set_enabled)(&mut features);
}
}

// Process all features declared in the code.
for attr in krate_attrs {
for mi in feature_list(attr) {
Expand All @@ -107,38 +69,6 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
}
};

// If the declared feature is an edition umbrella feature-gate,
// warn if it was redundant w.r.t. `crate_edition`.
// - E.g. warn if `rust_2018_preview` is declared when
// `crate_edition` is 2018
// - E.g. don't warn if `rust_2018_preview` is declared when
// `crate_edition` is 2015.
if let Some(&edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
if edition <= crate_edition {
sess.emit_warning(FeatureIncludedInEdition {
span: mi.span(),
feature: name,
edition,
});
}
features.set_declared_lang_feature(name, mi.span(), None);
continue;
}

// If the declared feature is edition-dependent and was already
// enabled due to `feature_edition`, give a warning.
// - E.g. warn if `test_2018_feature` is declared when
// `feature_edition` is 2018 or higher.
if edition_enabled_features.contains(&name) {
sess.emit_warning(FeatureIncludedInEdition {
span: mi.span(),
feature: name,
edition: features_edition,
});
features.set_declared_lang_feature(name, mi.span(), None);
continue;
}

// If the declared feature has been removed, issue an error.
if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) {
sess.emit_err(FeatureRemoved {
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_expand/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use rustc_ast::ast;
use rustc_macros::Diagnostic;
use rustc_session::Limit;
use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
use rustc_span::{Span, Symbol};
use std::borrow::Cow;
Expand Down Expand Up @@ -168,15 +167,6 @@ pub(crate) struct TakesNoArguments<'a> {
pub name: &'a str,
}

#[derive(Diagnostic)]
#[diag(expand_feature_included_in_edition, code = "E0705")]
pub(crate) struct FeatureIncludedInEdition {
#[primary_span]
pub span: Span,
pub feature: Symbol,
pub edition: Edition,
}

#[derive(Diagnostic)]
#[diag(expand_feature_removed, code = "E0557")]
pub(crate) struct FeatureRemoved<'a> {
Expand Down
Loading

0 comments on commit 54d6bde

Please sign in to comment.