Skip to content

Commit ded5475

Browse files
committed
Auto merge of #131321 - RalfJung:feature-activation, r=<try>
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 883f9a2 + 6c38ef0 commit ded5475

File tree

121 files changed

+389
-406
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+389
-406
lines changed

compiler/rustc_ast_lowering/src/asm.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
4949
| asm::InlineAsmArch::RiscV64
5050
| asm::InlineAsmArch::LoongArch64
5151
);
52-
if !is_stable && !self.tcx.features().asm_experimental_arch {
52+
if !is_stable && !self.tcx.features().asm_experimental_arch() {
5353
feature_err(
5454
&self.tcx.sess,
5555
sym::asm_experimental_arch,
@@ -65,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
6565
{
6666
self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
6767
}
68-
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
68+
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind() {
6969
feature_err(
7070
&self.tcx.sess,
7171
sym::asm_unwind,
@@ -237,7 +237,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
237237
}
238238
}
239239
InlineAsmOperand::Label { block } => {
240-
if !self.tcx.features().asm_goto {
240+
if !self.tcx.features().asm_goto() {
241241
feature_err(
242242
sess,
243243
sym::asm_goto,

compiler/rustc_ast_lowering/src/expr.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
575575
} else {
576576
// Either `body.is_none()` or `is_never_pattern` here.
577577
if !is_never_pattern {
578-
if self.tcx.features().never_patterns {
578+
if self.tcx.features().never_patterns() {
579579
// If the feature is off we already emitted the error after parsing.
580580
let suggestion = span.shrink_to_hi();
581581
self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
@@ -716,7 +716,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
716716
outer_hir_id: HirId,
717717
inner_hir_id: HirId,
718718
) {
719-
if self.tcx.features().async_fn_track_caller
719+
if self.tcx.features().async_fn_track_caller()
720720
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
721721
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
722722
{
@@ -1571,7 +1571,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15711571
);
15721572
}
15731573
Some(hir::CoroutineKind::Coroutine(_)) => {
1574-
if !self.tcx.features().coroutines {
1574+
if !self.tcx.features().coroutines() {
15751575
rustc_session::parse::feature_err(
15761576
&self.tcx.sess,
15771577
sym::coroutines,
@@ -1583,7 +1583,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15831583
false
15841584
}
15851585
None => {
1586-
if !self.tcx.features().coroutines {
1586+
if !self.tcx.features().coroutines() {
15871587
rustc_session::parse::feature_err(
15881588
&self.tcx.sess,
15891589
sym::coroutines,

compiler/rustc_ast_lowering/src/item.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1512,7 +1512,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15121512
continue;
15131513
}
15141514
let is_param = *is_param.get_or_insert_with(compute_is_param);
1515-
if !is_param && !self.tcx.features().more_maybe_bounds {
1515+
if !is_param && !self.tcx.features().more_maybe_bounds() {
15161516
self.tcx
15171517
.sess
15181518
.create_feature_err(
@@ -1530,7 +1530,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15301530
let host_param_parts = if let Const::Yes(span) = constness
15311531
// if this comes from implementing a `const` trait, we must force constness to be appended
15321532
// to the impl item, no matter whether effects is enabled.
1533-
&& (self.tcx.features().effects || force_append_constness)
1533+
&& (self.tcx.features().effects() || force_append_constness)
15341534
{
15351535
let span = self.lower_span(span);
15361536
let param_node_id = self.next_node_id();

compiler/rustc_ast_lowering/src/lib.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
193193
impl_trait_defs: Vec::new(),
194194
impl_trait_bounds: Vec::new(),
195195
allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
196-
allow_gen_future: if tcx.features().async_fn_track_caller {
196+
allow_gen_future: if tcx.features().async_fn_track_caller() {
197197
[sym::gen_future, sym::closure_track_caller].into()
198198
} else {
199199
[sym::gen_future].into()
@@ -1030,7 +1030,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10301030
span: data.inputs_span,
10311031
})
10321032
};
1033-
if !self.tcx.features().return_type_notation
1033+
if !self.tcx.features().return_type_notation()
10341034
&& self.tcx.sess.is_nightly_build()
10351035
{
10361036
add_feature_diagnostics(
@@ -1155,7 +1155,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11551155
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
11561156
ast::GenericArg::Type(ty) => {
11571157
match &ty.kind {
1158-
TyKind::Infer if self.tcx.features().generic_arg_infer => {
1158+
TyKind::Infer if self.tcx.features().generic_arg_infer() => {
11591159
return GenericArg::Infer(hir::InferArg {
11601160
hir_id: self.lower_node_id(ty.id),
11611161
span: self.lower_span(ty.span),
@@ -1546,7 +1546,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15461546
}
15471547
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => {
15481548
if in_trait_or_impl.is_some()
1549-
|| self.tcx.features().lifetime_capture_rules_2024
1549+
|| self.tcx.features().lifetime_capture_rules_2024()
15501550
|| span.at_least_rust_2024()
15511551
{
15521552
// return-position impl trait in trait was decided to capture all
@@ -2315,7 +2315,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23152315
fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
23162316
match c.value.kind {
23172317
ExprKind::Underscore => {
2318-
if self.tcx.features().generic_arg_infer {
2318+
if self.tcx.features().generic_arg_infer() {
23192319
hir::ArrayLen::Infer(hir::InferArg {
23202320
hir_id: self.lower_node_id(c.id),
23212321
span: self.lower_span(c.value.span),
@@ -2497,7 +2497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24972497
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
24982498
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
24992499
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
2500-
if self.tcx.features().negative_bounds {
2500+
if self.tcx.features().negative_bounds() {
25012501
hir::TraitBoundModifier::Negative
25022502
} else {
25032503
hir::TraitBoundModifier::None

compiler/rustc_ast_lowering/src/path.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
268268
span: data.inputs_span,
269269
})
270270
};
271-
if !self.tcx.features().return_type_notation
271+
if !self.tcx.features().return_type_notation()
272272
&& self.tcx.sess.is_nightly_build()
273273
{
274274
add_feature_diagnostics(
@@ -496,7 +496,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
496496
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
497497
// ```
498498
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
499-
if self.tcx.features().impl_trait_in_fn_trait_return {
499+
if self.tcx.features().impl_trait_in_fn_trait_return() {
500500
self.lower_ty(ty, itctx)
501501
} else {
502502
self.lower_ty(

compiler/rustc_ast_passes/src/ast_validation.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,8 @@ impl<'a> AstValidator<'a> {
332332
return;
333333
};
334334

335-
let make_impl_const_sugg = if self.features.const_trait_impl
335+
let const_trait_impl = self.features.const_trait_impl();
336+
let make_impl_const_sugg = if const_trait_impl
336337
&& let TraitOrTraitImpl::TraitImpl {
337338
constness: Const::No,
338339
polarity: ImplPolarity::Positive,
@@ -345,13 +346,12 @@ impl<'a> AstValidator<'a> {
345346
None
346347
};
347348

348-
let make_trait_const_sugg = if self.features.const_trait_impl
349-
&& let TraitOrTraitImpl::Trait { span, constness: None } = parent
350-
{
351-
Some(span.shrink_to_lo())
352-
} else {
353-
None
354-
};
349+
let make_trait_const_sugg =
350+
if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent {
351+
Some(span.shrink_to_lo())
352+
} else {
353+
None
354+
};
355355

356356
let parent_constness = parent.constness();
357357
self.dcx().emit_err(errors::TraitFnConst {
@@ -1185,7 +1185,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11851185
}
11861186
self.check_type_no_bounds(bounds, "this context");
11871187

1188-
if self.features.lazy_type_alias {
1188+
if self.features.lazy_type_alias() {
11891189
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
11901190
self.dcx().emit_err(err);
11911191
}
@@ -1326,7 +1326,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13261326
GenericBound::Trait(trait_ref, modifiers) => {
13271327
match (ctxt, modifiers.constness, modifiers.polarity) {
13281328
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
1329-
if !self.features.more_maybe_bounds =>
1329+
if !self.features.more_maybe_bounds() =>
13301330
{
13311331
self.sess
13321332
.create_feature_err(
@@ -1339,7 +1339,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13391339
.emit();
13401340
}
13411341
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
1342-
if !self.features.more_maybe_bounds =>
1342+
if !self.features.more_maybe_bounds() =>
13431343
{
13441344
self.sess
13451345
.create_feature_err(

compiler/rustc_ast_passes/src/feature_gate.rs

+52-50
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ use crate::errors;
1515
/// The common case.
1616
macro_rules! gate {
1717
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
18-
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
18+
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
1919
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
2020
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
2121
}
2222
}};
2323
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
24-
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
24+
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
2525
// FIXME: make this translatable
2626
#[allow(rustc::diagnostic_outside_of_impl)]
2727
#[allow(rustc::untranslatable_diagnostic)]
@@ -43,7 +43,7 @@ macro_rules! gate_alt {
4343
/// The case involving a multispan.
4444
macro_rules! gate_multi {
4545
($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{
46-
if !$visitor.features.$feature {
46+
if !$visitor.features.$feature() {
4747
let spans: Vec<_> =
4848
$spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
4949
if !spans.is_empty() {
@@ -56,7 +56,7 @@ macro_rules! gate_multi {
5656
/// The legacy case.
5757
macro_rules! gate_legacy {
5858
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
59-
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
59+
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
6060
feature_warn(&$visitor.sess, sym::$feature, $span, $explain);
6161
}
6262
}};
@@ -150,7 +150,7 @@ impl<'a> PostExpansionVisitor<'a> {
150150

151151
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
152152
// Let's keep users from using this feature accidentally.
153-
if self.features.non_lifetime_binders {
153+
if self.features.non_lifetime_binders() {
154154
let const_param_spans: Vec<_> = params
155155
.iter()
156156
.filter_map(|param| match param.kind {
@@ -210,7 +210,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
210210
}
211211

212212
// Emit errors for non-staged-api crates.
213-
if !self.features.staged_api {
213+
if !self.features.staged_api() {
214214
if attr.has_name(sym::unstable)
215215
|| attr.has_name(sym::stable)
216216
|| attr.has_name(sym::rustc_const_unstable)
@@ -470,7 +470,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
470470
// Limit `min_specialization` to only specializing functions.
471471
gate_alt!(
472472
&self,
473-
self.features.specialization || (is_fn && self.features.min_specialization),
473+
self.features.specialization() || (is_fn && self.features.min_specialization()),
474474
sym::specialization,
475475
i.span,
476476
"specialization is unstable"
@@ -548,7 +548,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
548548
gate_all!(global_registration, "global registration is experimental");
549549
gate_all!(return_type_notation, "return type notation is experimental");
550550

551-
if !visitor.features.never_patterns {
551+
if !visitor.features.never_patterns() {
552552
if let Some(spans) = spans.get(&sym::never_patterns) {
553553
for &span in spans {
554554
if span.allows_unstable(sym::never_patterns) {
@@ -572,7 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
572572
}
573573
}
574574

575-
if !visitor.features.negative_bounds {
575+
if !visitor.features.negative_bounds() {
576576
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
577577
sess.dcx().emit_err(errors::NegativeBoundUnsupported { span });
578578
}
@@ -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
{

0 commit comments

Comments
 (0)