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

terminology: #[feature] *activates* a feature (instead of "declaring" it) #131321

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
87 changes: 43 additions & 44 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,60 +600,61 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
}

fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
// checks if `#![feature]` has been used to enable any lang feature
// does not check the same for lib features unless there's at least one
// declared lang feature
if !sess.opts.unstable_features.is_nightly_build() {
if features.declared_features.is_empty() {
return;
}
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
let mut err = errors::FeatureOnNonNightly {
span: attr.span,
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
stable_features: vec![],
sugg: None,
};

let mut all_stable = true;
for ident in
attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
{
let name = ident.name;
let stable_since = features
.declared_lang_features
.iter()
.flat_map(|&(feature, _, since)| if feature == name { since } else { None })
.next();
if let Some(since) = stable_since {
err.stable_features.push(errors::StableFeature { name, since });
} else {
all_stable = false;
}
}
if all_stable {
err.sugg = Some(attr.span);
// checks if `#![feature]` has been used to enable any feature.
if sess.opts.unstable_features.is_nightly_build() {
return;
}
if features.active_features.is_empty() {
return;
}
let mut errored = false;
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
// `feature(...)` used on non-nightly. This is definitely an error.
let mut err = errors::FeatureOnNonNightly {
span: attr.span,
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
stable_features: vec![],
sugg: None,
};

let mut all_stable = true;
for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) {
let name = ident.name;
let stable_since = features
.active_lang_features
.iter()
.flat_map(|&(feature, _, since)| if feature == name { since } else { None })
.next();
if let Some(since) = stable_since {
err.stable_features.push(errors::StableFeature { name, since });
} else {
all_stable = false;
}
sess.dcx().emit_err(err);
}
if all_stable {
err.sugg = Some(attr.span);
}
sess.dcx().emit_err(err);
errored = true;
}
// Just make sure we actually error if anything is listed in `active_features`.
assert!(errored);
}

fn check_incompatible_features(sess: &Session, features: &Features) {
let declared_features = features
.declared_lang_features
let active_features = features
.active_lang_features
.iter()
.copied()
.map(|(name, span, _)| (name, span))
.chain(features.declared_lib_features.iter().copied());
.chain(features.active_lib_features.iter().copied());

for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
.iter()
.filter(|&&(f1, f2)| features.active(f1) && features.active(f2))
{
if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) {
if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
{
if let Some((f1_name, f1_span)) = active_features.clone().find(|(name, _)| name == f1) {
if let Some((f2_name, f2_span)) = active_features.clone().find(|(name, _)| name == f2) {
let spans = vec![f1_span, f2_span];
sess.dcx().emit_err(errors::IncompatibleFeatures {
spans,
Expand All @@ -671,10 +672,8 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) {
}

// Ban GCE with the new solver, because it does not implement GCE correctly.
if let Some(&(_, gce_span, _)) = features
.declared_lang_features
.iter()
.find(|&&(feat, _, _)| feat == sym::generic_const_exprs)
if let Some(&(_, gce_span, _)) =
features.active_lang_features.iter().find(|&&(feat, _, _)| feat == sym::generic_const_exprs)
{
sess.dcx().emit_err(errors::IncompatibleFeatures {
spans: vec![gce_span],
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,10 +699,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Calling an unstable function *always* requires that the corresponding gate
// (or implied gate) be enabled, even if the function has
// `#[rustc_allow_const_fn_unstable(the_gate)]`.
let gate_declared = |gate| tcx.features().declared(gate);
let feature_gate_declared = gate_declared(gate);
let implied_gate_declared = implied_by.is_some_and(gate_declared);
if !feature_gate_declared && !implied_gate_declared {
let gate_active = |gate| tcx.features().active(gate);
let feature_gate_active = gate_active(gate);
let implied_gate_active = implied_by.is_some_and(gate_active);
if !feature_gate_active && !implied_gate_active {
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
return;
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_error_codes/src/error_codes/E0636.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
A `#![feature]` attribute was declared multiple times.
The same feature is activated multiple times with `#![feature]` attributes

Erroneous code example:

```compile_fail,E0636
#![allow(stable_features)]
#![feature(rust1)]
#![feature(rust1)] // error: the feature `rust1` has already been declared
#![feature(rust1)] // error: the feature `rust1` has already been activated
```
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0705.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#### Note: this error code is no longer emitted by the compiler.

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

Erroneous code example:
Expand Down
16 changes: 8 additions & 8 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -

let mut features = Features::default();

// Process all features declared in the code.
// Process all features activated in the code.
for attr in krate_attrs {
for mi in feature_list(attr) {
let name = match mi.ident() {
Expand All @@ -75,7 +75,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
}
};

// If the declared feature has been removed, issue an error.
// If the activated feature has been removed, issue an error.
if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) {
sess.dcx().emit_err(FeatureRemoved {
span: mi.span(),
Expand All @@ -84,14 +84,14 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
continue;
}

// If the declared feature is stable, record it.
// If the activated feature is stable, record it.
if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
let since = Some(Symbol::intern(f.since));
features.set_declared_lang_feature(name, mi.span(), since);
features.set_active_lang_feature(name, mi.span(), since);
continue;
}

// If `-Z allow-features` is used and the declared feature is
// If `-Z allow-features` is used and the activated feature is
// unstable and not also listed as one of the allowed features,
// issue an error.
if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
Expand All @@ -101,7 +101,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
}
}

// If the declared feature is unstable, record it.
// If the activated feature is unstable, record it.
if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) {
(f.set_enabled)(&mut features);
// When the ICE comes from core, alloc or std (approximation of the standard
Expand All @@ -114,13 +114,13 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
{
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
}
features.set_declared_lang_feature(name, mi.span(), None);
features.set_active_lang_feature(name, mi.span(), None);
continue;
}

// Otherwise, the feature is unknown. Record it as a lib feature.
// It will be checked later.
features.set_declared_lib_feature(name, mi.span());
features.set_active_lib_feature(name, mi.span());

// Similar to above, detect internal lib features to suppress
// the ICE message that asks for a report.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/mbe/quoted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub(super) fn parse(
result
}

/// Asks for the `macro_metavar_expr` feature if it is not already declared
/// Asks for the `macro_metavar_expr` feature if it is not activated
fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) {
if !features.macro_metavar_expr {
let msg = "meta-variable expressions are unstable";
Expand Down
52 changes: 21 additions & 31 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,61 +54,48 @@ macro_rules! declare_features {
#[derive(Clone, Default, Debug)]
pub struct Features {
/// `#![feature]` attrs for language features, for error reporting.
/// "declared" here means that the feature is actually enabled in the current crate.
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
pub active_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
/// `#![feature]` attrs for non-language (library) features.
/// "declared" here means that the feature is actually enabled in the current crate.
pub declared_lib_features: Vec<(Symbol, Span)>,
/// `declared_lang_features` + `declared_lib_features`.
pub declared_features: FxHashSet<Symbol>,
/// Active state of individual features (unstable only).
pub active_lib_features: Vec<(Symbol, Span)>,
/// `active_lang_features` + `active_lib_features`.
pub active_features: FxHashSet<Symbol>,
/// Active state of individual features (unstable lang features only).
/// This is `true` if and only if the corresponding feature is listed in `active_lang_features`.
$(
$(#[doc = $doc])*
pub $feature: bool
),+
}

impl Features {
pub fn set_declared_lang_feature(
pub fn set_active_lang_feature(
&mut self,
symbol: Symbol,
span: Span,
since: Option<Symbol>
) {
self.declared_lang_features.push((symbol, span, since));
self.declared_features.insert(symbol);
self.active_lang_features.push((symbol, span, since));
self.active_features.insert(symbol);
}

pub fn set_declared_lib_feature(&mut self, symbol: Symbol, span: Span) {
self.declared_lib_features.push((symbol, span));
self.declared_features.insert(symbol);
pub fn set_active_lib_feature(&mut self, symbol: Symbol, span: Span) {
self.active_lib_features.push((symbol, span));
self.active_features.insert(symbol);
}

/// This is intended for hashing the set of active features.
/// This is intended for hashing the set of active language features.
///
/// The expectation is that this produces much smaller code than other alternatives.
///
/// Note that the total feature count is pretty small, so this is not a huge array.
#[inline]
pub fn all_features(&self) -> [u8; NUM_FEATURES] {
pub fn all_lang_features(&self) -> [u8; NUM_FEATURES] {
[$(self.$feature as u8),+]
}

/// Is the given feature explicitly declared, i.e. named in a
/// `#![feature(...)]` within the code?
pub fn declared(&self, feature: Symbol) -> bool {
self.declared_features.contains(&feature)
}

/// Is the given feature active (enabled by the user)?
///
/// Panics if the symbol doesn't correspond to a declared feature.
pub fn active(&self, feature: Symbol) -> bool {
match feature {
$( sym::$feature => self.$feature, )*

_ => panic!("`{}` was not listed in `declare_features`", feature),
}
self.active_features.contains(&feature)
}

/// Some features are known to be incomplete and using them is likely to have
Expand All @@ -119,8 +106,11 @@ macro_rules! declare_features {
$(
sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete,
)*
// Accepted/removed features aren't in this file but are never incomplete.
_ if self.declared_features.contains(&feature) => false,
_ if self.active_features.contains(&feature) => {
// Accepted/removed features and library features aren't in this file but
// are never incomplete.
false
}
_ => panic!("`{}` was not listed in `declare_features`", feature),
}
}
Expand All @@ -132,7 +122,7 @@ macro_rules! declare_features {
$(
sym::$feature => status_to_enum!($status) == FeatureStatus::Internal,
)*
_ if self.declared_features.contains(&feature) => {
_ if self.active_features.contains(&feature) => {
// This could be accepted/removed, or a libs feature.
// Accepted/removed features aren't in this file but are never internal
// (a removed feature might have been internal, but that's now irrelevant).
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2288,10 +2288,10 @@ impl EarlyLintPass for IncompleteInternalFeatures {
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
let features = cx.builder.features();
features
.declared_lang_features
.active_lang_features
.iter()
.map(|(name, span, _)| (name, span))
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
.chain(features.active_lib_features.iter().map(|(name, span)| (name, span)))
.filter(|(&name, _)| features.incomplete(name) || features.internal(name))
.for_each(|(&name, &span)| {
if features.incomplete(name) {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,15 +422,15 @@ impl<'tcx> TyCtxt<'tcx> {
debug!("stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
if self.features().declared(feature) {
if self.features().active(feature) {
return EvalResult::Allow;
}

// If this item was previously part of a now-stabilized feature which is still
// active (i.e. the user hasn't removed the attribute for the stabilized feature
// yet) then allow use of this item.
if let Some(implied_by) = implied_by
&& self.features().declared(implied_by)
&& self.features().active(implied_by)
{
return EvalResult::Allow;
}
Expand Down Expand Up @@ -509,7 +509,7 @@ impl<'tcx> TyCtxt<'tcx> {
debug!("body stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
if self.features().declared(feature) {
if self.features().active(feature) {
return EvalResult::Allow;
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3092,7 +3092,7 @@ impl<'tcx> TyCtxt<'tcx> {
Some(stability) if stability.is_const_unstable() => {
// has a `rustc_const_unstable` attribute, check whether the user enabled the
// corresponding feature gate.
self.features().declared(stability.feature)
self.features().active(stability.feature)
}
// functions without const stability are either stable user written
// const fn or the user is using feature gates and we thus don't
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ passes_duplicate_diagnostic_item_in_crate =
.note = the diagnostic item is first defined in crate `{$orig_crate_name}`

passes_duplicate_feature_err =
the feature `{$feature}` has already been declared
the feature `{$feature}` has already been activated

passes_duplicate_lang_item =
found duplicate lang item `{$lang_item_name}`
Expand Down
Loading
Loading