Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit bca5fde

Browse files
committed
Auto merge of #131321 - RalfJung:feature-activation, r=nnethercote
terminology: #[feature] *enables* a feature (instead of "declaring" or "activating" it) Mostly, we currently call a feature that has a corresponding `#[feature(name)]` attribute in the current crate a "declared" feature. I think that is confusing as it does not align with what "declaring" usually means. Furthermore, we *also* refer to `#[stable]`/`#[unstable]` as *declaring* a feature (e.g. in [these diagnostics](https://github.com/rust-lang/rust/blob/f25e5abea229a6b6aa77b45e21cb784e785c6040/compiler/rustc_passes/messages.ftl#L297-L301)), which aligns better with what "declaring" usually means. To make things worse, the functions `tcx.features().active(...)` and `tcx.features().declared(...)` both exist and they are doing almost the same thing (testing whether a corresponding `#[feature(name)]` exists) except that `active` would ICE if the feature is not an unstable lang feature. On top of this, the callback when a feature is activated/declared is called `set_enabled`, and many comments also talk about "enabling" a feature. So really, our terminology is just a mess. I would suggest we use "declaring a feature" for saying that something is/was guarded by a feature (e.g. `#[stable]`/`#[unstable]`), and "enabling a feature" for `#[feature(name)]`. This PR implements that.
2 parents 916e9ce + 1381773 commit bca5fde

File tree

21 files changed

+151
-129
lines changed

21 files changed

+151
-129
lines changed

‎compiler/rustc_ast_passes/src/feature_gate.rs‎

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -600,59 +600,61 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
600600
}
601601

602602
fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
603-
// checks if `#![feature]` has been used to enable any lang feature
604-
// does not check the same for lib features unless there's at least one
605-
// declared lang feature
606-
if !sess.opts.unstable_features.is_nightly_build() {
607-
if features.declared_features.is_empty() {
608-
return;
609-
}
610-
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
611-
let mut err = errors::FeatureOnNonNightly {
612-
span: attr.span,
613-
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
614-
stable_features: vec![],
615-
sugg: None,
616-
};
617-
618-
let mut all_stable = true;
619-
for ident in
620-
attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
621-
{
622-
let name = ident.name;
623-
let stable_since = features
624-
.declared_lang_features
625-
.iter()
626-
.flat_map(|&(feature, _, since)| if feature == name { since } else { None })
627-
.next();
628-
if let Some(since) = stable_since {
629-
err.stable_features.push(errors::StableFeature { name, since });
630-
} else {
631-
all_stable = false;
632-
}
633-
}
634-
if all_stable {
635-
err.sugg = Some(attr.span);
603+
// checks if `#![feature]` has been used to enable any feature.
604+
if sess.opts.unstable_features.is_nightly_build() {
605+
return;
606+
}
607+
if features.enabled_features().is_empty() {
608+
return;
609+
}
610+
let mut errored = false;
611+
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
612+
// `feature(...)` used on non-nightly. This is definitely an error.
613+
let mut err = errors::FeatureOnNonNightly {
614+
span: attr.span,
615+
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
616+
stable_features: vec![],
617+
sugg: None,
618+
};
619+
620+
let mut all_stable = true;
621+
for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) {
622+
let name = ident.name;
623+
let stable_since = features
624+
.enabled_lang_features()
625+
.iter()
626+
.flat_map(|&(feature, _, since)| if feature == name { since } else { None })
627+
.next();
628+
if let Some(since) = stable_since {
629+
err.stable_features.push(errors::StableFeature { name, since });
630+
} else {
631+
all_stable = false;
636632
}
637-
sess.dcx().emit_err(err);
638633
}
634+
if all_stable {
635+
err.sugg = Some(attr.span);
636+
}
637+
sess.dcx().emit_err(err);
638+
errored = true;
639639
}
640+
// Just make sure we actually error if anything is listed in `enabled_features`.
641+
assert!(errored);
640642
}
641643

642644
fn check_incompatible_features(sess: &Session, features: &Features) {
643-
let declared_features = features
644-
.declared_lang_features
645+
let enabled_features = features
646+
.enabled_lang_features()
645647
.iter()
646648
.copied()
647649
.map(|(name, span, _)| (name, span))
648-
.chain(features.declared_lib_features.iter().copied());
650+
.chain(features.enabled_lib_features().iter().copied());
649651

650652
for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
651653
.iter()
652-
.filter(|&&(f1, f2)| features.active(f1) && features.active(f2))
654+
.filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2))
653655
{
654-
if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) {
655-
if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
656+
if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) {
657+
if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
656658
{
657659
let spans = vec![f1_span, f2_span];
658660
sess.dcx().emit_err(errors::IncompatibleFeatures {
@@ -672,7 +674,7 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) {
672674

673675
// Ban GCE with the new solver, because it does not implement GCE correctly.
674676
if let Some(&(_, gce_span, _)) = features
675-
.declared_lang_features
677+
.enabled_lang_features()
676678
.iter()
677679
.find(|&&(feat, _, _)| feat == sym::generic_const_exprs)
678680
{

‎compiler/rustc_const_eval/src/check_consts/check.rs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
276276
let gate = match op.status_in_item(self.ccx) {
277277
Status::Allowed => return,
278278

279-
Status::Unstable(gate) if self.tcx.features().active(gate) => {
279+
Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
280280
let unstable_in_stable = self.ccx.is_const_stable_const_fn()
281281
&& !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
282282
if unstable_in_stable {
@@ -700,10 +700,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
700700
// Calling an unstable function *always* requires that the corresponding gate
701701
// (or implied gate) be enabled, even if the function has
702702
// `#[rustc_allow_const_fn_unstable(the_gate)]`.
703-
let gate_declared = |gate| tcx.features().declared(gate);
704-
let feature_gate_declared = gate_declared(gate);
705-
let implied_gate_declared = implied_by.is_some_and(gate_declared);
706-
if !feature_gate_declared && !implied_gate_declared {
703+
let gate_enabled = |gate| tcx.features().enabled(gate);
704+
let feature_gate_enabled = gate_enabled(gate);
705+
let implied_gate_enabled = implied_by.is_some_and(gate_enabled);
706+
if !feature_gate_enabled && !implied_gate_enabled {
707707
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
708708
return;
709709
}
@@ -717,7 +717,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
717717

718718
// Otherwise, we are something const-stable calling a const-unstable fn.
719719
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
720-
trace!("rustc_allow_const_fn_unstable gate active");
720+
trace!("rustc_allow_const_fn_unstable gate enabled");
721721
return;
722722
}
723723

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
A `#![feature]` attribute was declared multiple times.
1+
The same feature is enabled multiple times with `#![feature]` attributes
22

33
Erroneous code example:
44

55
```compile_fail,E0636
66
#![allow(stable_features)]
77
#![feature(rust1)]
8-
#![feature(rust1)] // error: the feature `rust1` has already been declared
8+
#![feature(rust1)] // error: the feature `rust1` has already been enabled
99
```

‎compiler/rustc_error_codes/src/error_codes/E0705.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#### Note: this error code is no longer emitted by the compiler.
22

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

66
Erroneous code example:

‎compiler/rustc_expand/src/config.rs‎

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
5252

5353
let mut features = Features::default();
5454

55-
// Process all features declared in the code.
55+
// Process all features enabled in the code.
5656
for attr in krate_attrs {
5757
for mi in feature_list(attr) {
5858
let name = match mi.ident() {
@@ -76,7 +76,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
7676
}
7777
};
7878

79-
// If the declared feature has been removed, issue an error.
79+
// If the enabled feature has been removed, issue an error.
8080
if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) {
8181
sess.dcx().emit_err(FeatureRemoved {
8282
span: mi.span(),
@@ -85,14 +85,14 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
8585
continue;
8686
}
8787

88-
// If the declared feature is stable, record it.
88+
// If the enabled feature is stable, record it.
8989
if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
9090
let since = Some(Symbol::intern(f.since));
91-
features.set_declared_lang_feature(name, mi.span(), since);
91+
features.set_enabled_lang_feature(name, mi.span(), since,None);
9292
continue;
9393
}
9494

95-
// If `-Z allow-features` is used and the declared feature is
95+
// If `-Z allow-features` is used and the enabled feature is
9696
// unstable and not also listed as one of the allowed features,
9797
// issue an error.
9898
if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
@@ -102,9 +102,8 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
102102
}
103103
}
104104

105-
// If the declared feature is unstable, record it.
105+
// If the enabled feature is unstable, record it.
106106
if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) {
107-
(f.set_enabled)(&mut features);
108107
// When the ICE comes from core, alloc or std (approximation of the standard
109108
// library), there's a chance that the person hitting the ICE may be using
110109
// -Zbuild-std or similar with an untested target. The bug is probably in the
@@ -115,13 +114,13 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
115114
{
116115
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
117116
}
118-
features.set_declared_lang_feature(name, mi.span(), None);
117+
features.set_enabled_lang_feature(name, mi.span(), None,Some(f));
119118
continue;
120119
}
121120

122-
// Otherwise, the feature is unknown. Record it as a lib feature.
123-
// It will be checked later.
124-
features.set_declared_lib_feature(name, mi.span());
121+
// Otherwise, the feature is unknown. Enable it as a lib feature.
122+
// It will be checked later whether the feature really exists.
123+
features.set_enabled_lib_feature(name, mi.span());
125124

126125
// Similar to above, detect internal lib features to suppress
127126
// the ICE message that asks for a report.

‎compiler/rustc_expand/src/mbe/quoted.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub(super) fn parse(
119119
result
120120
}
121121

122-
/// Asks for the `macro_metavar_expr` feature if it is not already declared
122+
/// Asks for the `macro_metavar_expr` feature if it is not enabled
123123
fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) {
124124
if !features.macro_metavar_expr {
125125
let msg = "meta-variable expressions are unstable";

‎compiler/rustc_feature/src/unstable.rs‎

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use super::{Feature, to_nonzero};
88

99
pub struct UnstableFeature {
1010
pub feature: Feature,
11-
pubset_enabled: fn(&mut Features),
11+
set_enabled: fn(&mut Features),
1212
}
1313

1414
#[derive(PartialEq)]
@@ -54,61 +54,85 @@ macro_rules! declare_features {
5454
#[derive(Clone, Default, Debug)]
5555
pub struct Features {
5656
/// `#![feature]` attrs for language features, for error reporting.
57-
/// "declared" here means that the feature is actually enabled in the current crate.
58-
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
57+
enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
5958
/// `#![feature]` attrs for non-language (library) features.
60-
/// "declared" here means that the feature is actually enabled in the current crate.
61-
pub declared_lib_features:Vec<(Symbol,Span)>,
62-
/// `declared_lang_features` + `declared_lib_features`.
63-
pub declared_features:FxHashSet<Symbol>,
64-
/// Active state of individual features (unstable only).
59+
enabled_lib_features:Vec<(Symbol,Span)>,
60+
/// `enabled_lang_features` + `enabled_lib_features`.
61+
enabled_features:FxHashSet<Symbol>,
62+
/// State of individual features (unstable lang features only).
63+
/// This is `true` if and only if the corresponding feature is listed in `enabled_lang_features`.
6564
$(
6665
$(#[doc = $doc])*
6766
pub $feature: bool
6867
),+
6968
}
7069

7170
impl Features {
72-
pub fn set_declared_lang_feature(
71+
pub fn set_enabled_lang_feature(
7372
&mut self,
74-
symbol: Symbol,
73+
name: Symbol,
7574
span: Span,
76-
since: Option<Symbol>
75+
since: Option<Symbol>,
76+
feature: Option<&UnstableFeature>,
7777
) {
78-
self.declared_lang_features.push((symbol, span, since));
79-
self.declared_features.insert(symbol);
78+
self.enabled_lang_features.push((name, span, since));
79+
self.enabled_features.insert(name);
80+
if let Some(feature) = feature {
81+
assert_eq!(feature.feature.name, name);
82+
(feature.set_enabled)(self);
83+
} else {
84+
// Ensure we don't skip a `set_enabled` call.
85+
debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none());
86+
}
8087
}
8188

82-
pub fn set_declared_lib_feature(&mut self, symbol: Symbol, span: Span) {
83-
self.declared_lib_features.push((symbol, span));
84-
self.declared_features.insert(symbol);
89+
pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) {
90+
self.enabled_lib_features.push((name, span));
91+
self.enabled_features.insert(name);
92+
// Ensure we don't skip a `set_enabled` call.
93+
debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none());
8594
}
8695

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

97-
/// Is the given feature explicitly declared, i.e. named in a
98-
/// `#![feature(...)]` within the code?
99-
pub fn declared(&self, feature: Symbol) -> bool {
100-
self.declared_features.contains(&feature)
106+
pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> {
107+
&self.enabled_lang_features
101108
}
102109

103-
/// Is the given feature active (enabled by the user)?
104-
///
105-
/// Panics if the symbol doesn't correspond to a declared feature.
106-
pub fn active(&self, feature: Symbol) -> bool {
107-
match feature {
108-
$( sym::$feature => self.$feature, )*
110+
pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> {
111+
&self.enabled_lib_features
112+
}
109113

110-
_ => panic!("`{}` was not listed in `declare_features`", feature),
114+
pub fn enabled_features(&self) -> &FxHashSet<Symbol> {
115+
&self.enabled_features
116+
}
117+
118+
/// Is the given feature enabled (via `#[feature(...)]`)?
119+
pub fn enabled(&self, feature: Symbol) -> bool {
120+
let e = self.enabled_features.contains(&feature);
121+
if cfg!(debug_assertions) {
122+
// Ensure this matches `self.$feature`, if that exists.
123+
let e2 = match feature {
124+
$( sym::$feature => Some(self.$feature), )*
125+
_ => None,
126+
};
127+
if let Some(e2) = e2 {
128+
assert_eq!(
129+
e, e2,
130+
"mismatch in feature state for `{feature}`: \
131+
`enabled_features` says {e} but `self.{feature}` says {e2}"
132+
);
133+
}
111134
}
135+
e
112136
}
113137

114138
/// Some features are known to be incomplete and using them is likely to have
@@ -119,8 +143,11 @@ macro_rules! declare_features {
119143
$(
120144
sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete,
121145
)*
122-
// Accepted/removed features aren't in this file but are never incomplete.
123-
_ if self.declared_features.contains(&feature) => false,
146+
_ if self.enabled_features.contains(&feature) => {
147+
// Accepted/removed features and library features aren't in this file but
148+
// are never incomplete.
149+
false
150+
}
124151
_ => panic!("`{}` was not listed in `declare_features`", feature),
125152
}
126153
}
@@ -132,7 +159,7 @@ macro_rules! declare_features {
132159
$(
133160
sym::$feature => status_to_enum!($status) == FeatureStatus::Internal,
134161
)*
135-
_ if self.declared_features.contains(&feature) => {
162+
_ if self.enabled_features.contains(&feature) => {
136163
// This could be accepted/removed, or a libs feature.
137164
// Accepted/removed features aren't in this file but are never internal
138165
// (a removed feature might have been internal, but that's now irrelevant).

‎compiler/rustc_lint/src/builtin.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,10 +2288,10 @@ impl EarlyLintPass for IncompleteInternalFeatures {
22882288
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
22892289
let features = cx.builder.features();
22902290
features
2291-
.declared_lang_features
2291+
.enabled_lang_features()
22922292
.iter()
22932293
.map(|(name, span, _)| (name, span))
2294-
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
2294+
.chain(features.enabled_lib_features().iter().map(|(name, span)| (name, span)))
22952295
.filter(|(&name, _)| features.incomplete(name) || features.internal(name))
22962296
.for_each(|(&name, &span)| {
22972297
if features.incomplete(name) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /