nightly feature tracking: get rid of the per-feature bool fields

This commit is contained in:
Ralf Jung 2024-10-09 09:01:57 +02:00
parent e1f3068995
commit ad3991d303
108 changed files with 299 additions and 331 deletions

View File

@ -49,7 +49,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| asm::InlineAsmArch::RiscV64 | asm::InlineAsmArch::RiscV64
| asm::InlineAsmArch::LoongArch64 | asm::InlineAsmArch::LoongArch64
); );
if !is_stable && !self.tcx.features().asm_experimental_arch { if !is_stable && !self.tcx.features().asm_experimental_arch() {
feature_err( feature_err(
&self.tcx.sess, &self.tcx.sess,
sym::asm_experimental_arch, sym::asm_experimental_arch,
@ -65,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
{ {
self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp }); self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
} }
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind { if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind() {
feature_err( feature_err(
&self.tcx.sess, &self.tcx.sess,
sym::asm_unwind, sym::asm_unwind,
@ -237,7 +237,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
InlineAsmOperand::Label { block } => { InlineAsmOperand::Label { block } => {
if !self.tcx.features().asm_goto { if !self.tcx.features().asm_goto() {
feature_err( feature_err(
sess, sess,
sym::asm_goto, sym::asm_goto,

View File

@ -575,7 +575,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} else { } else {
// Either `body.is_none()` or `is_never_pattern` here. // Either `body.is_none()` or `is_never_pattern` here.
if !is_never_pattern { if !is_never_pattern {
if self.tcx.features().never_patterns { if self.tcx.features().never_patterns() {
// If the feature is off we already emitted the error after parsing. // If the feature is off we already emitted the error after parsing.
let suggestion = span.shrink_to_hi(); let suggestion = span.shrink_to_hi();
self.dcx().emit_err(MatchArmWithNoBody { span, suggestion }); self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
@ -717,7 +717,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
outer_hir_id: HirId, outer_hir_id: HirId,
inner_hir_id: HirId, inner_hir_id: HirId,
) { ) {
if self.tcx.features().async_fn_track_caller if self.tcx.features().async_fn_track_caller()
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
{ {
@ -1572,7 +1572,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
} }
Some(hir::CoroutineKind::Coroutine(_)) => { Some(hir::CoroutineKind::Coroutine(_)) => {
if !self.tcx.features().coroutines { if !self.tcx.features().coroutines() {
rustc_session::parse::feature_err( rustc_session::parse::feature_err(
&self.tcx.sess, &self.tcx.sess,
sym::coroutines, sym::coroutines,
@ -1584,7 +1584,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
false false
} }
None => { None => {
if !self.tcx.features().coroutines { if !self.tcx.features().coroutines() {
rustc_session::parse::feature_err( rustc_session::parse::feature_err(
&self.tcx.sess, &self.tcx.sess,
sym::coroutines, sym::coroutines,

View File

@ -1512,7 +1512,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
continue; continue;
} }
let is_param = *is_param.get_or_insert_with(compute_is_param); let is_param = *is_param.get_or_insert_with(compute_is_param);
if !is_param && !self.tcx.features().more_maybe_bounds { if !is_param && !self.tcx.features().more_maybe_bounds() {
self.tcx self.tcx
.sess .sess
.create_feature_err( .create_feature_err(
@ -1530,7 +1530,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let host_param_parts = if let Const::Yes(span) = constness let host_param_parts = if let Const::Yes(span) = constness
// if this comes from implementing a `const` trait, we must force constness to be appended // if this comes from implementing a `const` trait, we must force constness to be appended
// to the impl item, no matter whether effects is enabled. // to the impl item, no matter whether effects is enabled.
&& (self.tcx.features().effects || force_append_constness) && (self.tcx.features().effects() || force_append_constness)
{ {
let span = self.lower_span(span); let span = self.lower_span(span);
let param_node_id = self.next_node_id(); let param_node_id = self.next_node_id();

View File

@ -193,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
impl_trait_defs: Vec::new(), impl_trait_defs: Vec::new(),
impl_trait_bounds: Vec::new(), impl_trait_bounds: Vec::new(),
allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(), allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
allow_gen_future: if tcx.features().async_fn_track_caller { allow_gen_future: if tcx.features().async_fn_track_caller() {
[sym::gen_future, sym::closure_track_caller].into() [sym::gen_future, sym::closure_track_caller].into()
} else { } else {
[sym::gen_future].into() [sym::gen_future].into()
@ -1035,7 +1035,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: data.inputs_span, span: data.inputs_span,
}) })
}; };
if !self.tcx.features().return_type_notation if !self.tcx.features().return_type_notation()
&& self.tcx.sess.is_nightly_build() && self.tcx.sess.is_nightly_build()
{ {
add_feature_diagnostics( add_feature_diagnostics(
@ -1160,7 +1160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
ast::GenericArg::Type(ty) => { ast::GenericArg::Type(ty) => {
match &ty.kind { match &ty.kind {
TyKind::Infer if self.tcx.features().generic_arg_infer => { TyKind::Infer if self.tcx.features().generic_arg_infer() => {
return GenericArg::Infer(hir::InferArg { return GenericArg::Infer(hir::InferArg {
hir_id: self.lower_node_id(ty.id), hir_id: self.lower_node_id(ty.id),
span: self.lower_span(ty.span), span: self.lower_span(ty.span),
@ -1500,7 +1500,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// is enabled. We don't check the span of the edition, since this is done // is enabled. We don't check the span of the edition, since this is done
// on a per-opaque basis to account for nested opaques. // on a per-opaque basis to account for nested opaques.
let always_capture_in_scope = match origin { let always_capture_in_scope = match origin {
_ if self.tcx.features().lifetime_capture_rules_2024 => true, _ if self.tcx.features().lifetime_capture_rules_2024() => true,
hir::OpaqueTyOrigin::TyAlias { .. } => true, hir::OpaqueTyOrigin::TyAlias { .. } => true,
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
hir::OpaqueTyOrigin::AsyncFn { .. } => { hir::OpaqueTyOrigin::AsyncFn { .. } => {
@ -1519,7 +1519,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Feature gate for RPITIT + use<..> // Feature gate for RPITIT + use<..>
match origin { match origin {
rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => {
if !self.tcx.features().precise_capturing_in_traits if !self.tcx.features().precise_capturing_in_traits()
&& let Some(span) = bounds.iter().find_map(|bound| match *bound { && let Some(span) = bounds.iter().find_map(|bound| match *bound {
ast::GenericBound::Use(_, span) => Some(span), ast::GenericBound::Use(_, span) => Some(span),
_ => None, _ => None,
@ -2270,7 +2270,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> { fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
match c.value.kind { match c.value.kind {
ExprKind::Underscore => { ExprKind::Underscore => {
if self.tcx.features().generic_arg_infer { if self.tcx.features().generic_arg_infer() {
hir::ArrayLen::Infer(hir::InferArg { hir::ArrayLen::Infer(hir::InferArg {
hir_id: self.lower_node_id(c.id), hir_id: self.lower_node_id(c.id),
span: self.lower_span(c.value.span), span: self.lower_span(c.value.span),

View File

@ -268,7 +268,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: data.inputs_span, span: data.inputs_span,
}) })
}; };
if !self.tcx.features().return_type_notation if !self.tcx.features().return_type_notation()
&& self.tcx.sess.is_nightly_build() && self.tcx.sess.is_nightly_build()
{ {
add_feature_diagnostics( add_feature_diagnostics(
@ -496,7 +496,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^ // // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
// ``` // ```
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
if self.tcx.features().impl_trait_in_fn_trait_return { if self.tcx.features().impl_trait_in_fn_trait_return() {
self.lower_ty(ty, itctx) self.lower_ty(ty, itctx)
} else { } else {
self.lower_ty( self.lower_ty(

View File

@ -295,7 +295,8 @@ impl<'a> AstValidator<'a> {
return; return;
}; };
let make_impl_const_sugg = if self.features.const_trait_impl let const_trait_impl = self.features.const_trait_impl();
let make_impl_const_sugg = if const_trait_impl
&& let TraitOrTraitImpl::TraitImpl { && let TraitOrTraitImpl::TraitImpl {
constness: Const::No, constness: Const::No,
polarity: ImplPolarity::Positive, polarity: ImplPolarity::Positive,
@ -308,9 +309,8 @@ impl<'a> AstValidator<'a> {
None None
}; };
let make_trait_const_sugg = if self.features.const_trait_impl let make_trait_const_sugg =
&& let TraitOrTraitImpl::Trait { span, constness: None } = parent if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent {
{
Some(span.shrink_to_lo()) Some(span.shrink_to_lo())
} else { } else {
None None
@ -1145,7 +1145,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} }
self.check_type_no_bounds(bounds, "this context"); self.check_type_no_bounds(bounds, "this context");
if self.features.lazy_type_alias { if self.features.lazy_type_alias() {
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
self.dcx().emit_err(err); self.dcx().emit_err(err);
} }
@ -1286,7 +1286,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
GenericBound::Trait(trait_ref) => { GenericBound::Trait(trait_ref) => {
match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) { match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
if !self.features.more_maybe_bounds => if !self.features.more_maybe_bounds() =>
{ {
self.sess self.sess
.create_feature_err( .create_feature_err(
@ -1299,7 +1299,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.emit(); .emit();
} }
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
if !self.features.more_maybe_bounds => if !self.features.more_maybe_bounds() =>
{ {
self.sess self.sess
.create_feature_err( .create_feature_err(

View File

@ -15,13 +15,13 @@ use crate::errors;
/// The common case. /// The common case.
macro_rules! gate { macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit(); feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
} }
}}; }};
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
// FIXME: make this translatable // FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::untranslatable_diagnostic)]
@ -43,7 +43,7 @@ macro_rules! gate_alt {
/// The case involving a multispan. /// The case involving a multispan.
macro_rules! gate_multi { macro_rules! gate_multi {
($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{ ($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{
if !$visitor.features.$feature { if !$visitor.features.$feature() {
let spans: Vec<_> = let spans: Vec<_> =
$spans.filter(|span| !span.allows_unstable(sym::$feature)).collect(); $spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
if !spans.is_empty() { if !spans.is_empty() {
@ -56,7 +56,7 @@ macro_rules! gate_multi {
/// The legacy case. /// The legacy case.
macro_rules! gate_legacy { macro_rules! gate_legacy {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
feature_warn(&$visitor.sess, sym::$feature, $span, $explain); feature_warn(&$visitor.sess, sym::$feature, $span, $explain);
} }
}}; }};
@ -150,7 +150,7 @@ impl<'a> PostExpansionVisitor<'a> {
// FIXME(non_lifetime_binders): Const bound params are pretty broken. // FIXME(non_lifetime_binders): Const bound params are pretty broken.
// Let's keep users from using this feature accidentally. // Let's keep users from using this feature accidentally.
if self.features.non_lifetime_binders { if self.features.non_lifetime_binders() {
let const_param_spans: Vec<_> = params let const_param_spans: Vec<_> = params
.iter() .iter()
.filter_map(|param| match param.kind { .filter_map(|param| match param.kind {
@ -210,7 +210,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
} }
// Emit errors for non-staged-api crates. // Emit errors for non-staged-api crates.
if !self.features.staged_api { if !self.features.staged_api() {
if attr.has_name(sym::unstable) if attr.has_name(sym::unstable)
|| attr.has_name(sym::stable) || attr.has_name(sym::stable)
|| attr.has_name(sym::rustc_const_unstable) || attr.has_name(sym::rustc_const_unstable)
@ -470,7 +470,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
// Limit `min_specialization` to only specializing functions. // Limit `min_specialization` to only specializing functions.
gate_alt!( gate_alt!(
&self, &self,
self.features.specialization || (is_fn && self.features.min_specialization), self.features.specialization() || (is_fn && self.features.min_specialization()),
sym::specialization, sym::specialization,
i.span, i.span,
"specialization is unstable" "specialization is unstable"
@ -548,7 +548,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(return_type_notation, "return type notation is experimental");
gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
if !visitor.features.never_patterns { if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) { if let Some(spans) = spans.get(&sym::never_patterns) {
for &span in spans { for &span in spans {
if span.allows_unstable(sym::never_patterns) { if span.allows_unstable(sym::never_patterns) {
@ -572,7 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
} }
} }
if !visitor.features.negative_bounds { if !visitor.features.negative_bounds() {
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
sess.dcx().emit_err(errors::NegativeBoundUnsupported { span }); sess.dcx().emit_err(errors::NegativeBoundUnsupported { span });
} }

View File

@ -622,7 +622,7 @@ pub fn eval_condition(
&(( &((
if *b { kw::True } else { kw::False }, if *b { kw::True } else { kw::False },
sym::cfg_boolean_literals, sym::cfg_boolean_literals,
|features: &Features| features.cfg_boolean_literals, |features: &Features| features.cfg_boolean_literals(),
)), )),
cfg.span(), cfg.span(),
sess, sess,
@ -711,7 +711,7 @@ pub fn eval_condition(
} }
sym::target => { sym::target => {
if let Some(features) = features if let Some(features) = features
&& !features.cfg_target_compact && !features.cfg_target_compact()
{ {
feature_err( feature_err(
sess, sess,
@ -831,7 +831,7 @@ pub fn find_deprecation(
attrs: &[Attribute], attrs: &[Attribute],
) -> Option<(Deprecation, Span)> { ) -> Option<(Deprecation, Span)> {
let mut depr: Option<(Deprecation, Span)> = None; let mut depr: Option<(Deprecation, Span)> = None;
let is_rustc = features.staged_api; let is_rustc = features.staged_api();
'outer: for attr in attrs { 'outer: for attr in attrs {
if !attr.has_name(sym::deprecated) { if !attr.has_name(sym::deprecated) {
@ -891,7 +891,7 @@ pub fn find_deprecation(
} }
} }
sym::suggestion => { sym::suggestion => {
if !features.deprecated_suggestion { if !features.deprecated_suggestion() {
sess.dcx().emit_err( sess.dcx().emit_err(
session_diagnostics::DeprecatedItemSuggestion { session_diagnostics::DeprecatedItemSuggestion {
span: mi.span, span: mi.span,
@ -909,7 +909,7 @@ pub fn find_deprecation(
sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
span: meta.span(), span: meta.span(),
item: pprust::path_to_string(&mi.path), item: pprust::path_to_string(&mi.path),
expected: if features.deprecated_suggestion { expected: if features.deprecated_suggestion() {
&["since", "note", "suggestion"] &["since", "note", "suggestion"]
} else { } else {
&["since", "note"] &["since", "note"]

View File

@ -1035,7 +1035,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn unsized_feature_enabled(&self) -> bool { fn unsized_feature_enabled(&self) -> bool {
let features = self.tcx().features(); let features = self.tcx().features();
features.unsized_locals || features.unsized_fn_params features.unsized_locals() || features.unsized_fn_params()
} }
/// Equate the inferred type and the annotated type for user type annotations /// Equate the inferred type and the annotated type for user type annotations

View File

@ -69,7 +69,7 @@ pub(crate) fn expand_assert<'cx>(
// If `generic_assert` is enabled, generates rich captured outputs // If `generic_assert` is enabled, generates rich captured outputs
// //
// FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949 // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949
else if cx.ecfg.features.generic_assert { else if cx.ecfg.features.generic_assert() {
context::Context::new(cx, call_site_span).build(cond_expr, panic_path()) context::Context::new(cx, call_site_span).build(cond_expr, panic_path())
} }
// If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..." // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..."

View File

@ -137,7 +137,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
let inner = attr.meta_item_list(); let inner = attr.meta_item_list();
match inner.as_deref() { match inner.as_deref() {
Some([item]) if item.has_name(sym::linker) => { Some([item]) if item.has_name(sym::linker) => {
if !tcx.features().used_with_arg { if !tcx.features().used_with_arg() {
feature_err( feature_err(
&tcx.sess, &tcx.sess,
sym::used_with_arg, sym::used_with_arg,
@ -149,7 +149,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
} }
Some([item]) if item.has_name(sym::compiler) => { Some([item]) if item.has_name(sym::compiler) => {
if !tcx.features().used_with_arg { if !tcx.features().used_with_arg() {
feature_err( feature_err(
&tcx.sess, &tcx.sess,
sym::used_with_arg, sym::used_with_arg,
@ -213,7 +213,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
.emit(); .emit();
} }
if is_closure if is_closure
&& !tcx.features().closure_track_caller && !tcx.features().closure_track_caller()
&& !attr.span.allows_unstable(sym::closure_track_caller) && !attr.span.allows_unstable(sym::closure_track_caller)
{ {
feature_err( feature_err(
@ -268,7 +268,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// //
// This exception needs to be kept in sync with allowing // This exception needs to be kept in sync with allowing
// `#[target_feature]` on `main` and `start`. // `#[target_feature]` on `main` and `start`.
} else if !tcx.features().target_feature_11 { } else if !tcx.features().target_feature_11() {
feature_err( feature_err(
&tcx.sess, &tcx.sess,
sym::target_feature_11, sym::target_feature_11,
@ -584,7 +584,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// its parent function, which effectively inherits the features anyway. Boxing this closure // its parent function, which effectively inherits the features anyway. Boxing this closure
// would result in this closure being compiled without the inherited target features, but this // would result in this closure being compiled without the inherited target features, but this
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
if tcx.features().target_feature_11 if tcx.features().target_feature_11()
&& tcx.is_closure_like(did.to_def_id()) && tcx.is_closure_like(did.to_def_id())
&& codegen_fn_attrs.inline != InlineAttr::Always && codegen_fn_attrs.inline != InlineAttr::Always
{ {

View File

@ -63,27 +63,27 @@ pub(crate) fn from_target_feature(
// Only allow features whose feature gates have been enabled. // Only allow features whose feature gates have been enabled.
let allowed = match feature_gate.as_ref().copied() { let allowed = match feature_gate.as_ref().copied() {
Some(sym::arm_target_feature) => rust_features.arm_target_feature, Some(sym::arm_target_feature) => rust_features.arm_target_feature(),
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature(),
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature, Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature(),
Some(sym::mips_target_feature) => rust_features.mips_target_feature, Some(sym::mips_target_feature) => rust_features.mips_target_feature(),
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature, Some(sym::riscv_target_feature) => rust_features.riscv_target_feature(),
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, Some(sym::avx512_target_feature) => rust_features.avx512_target_feature(),
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature(),
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, Some(sym::tbm_target_feature) => rust_features.tbm_target_feature(),
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, Some(sym::wasm_target_feature) => rust_features.wasm_target_feature(),
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, Some(sym::rtm_target_feature) => rust_features.rtm_target_feature(),
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature, Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature(),
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, Some(sym::bpf_target_feature) => rust_features.bpf_target_feature(),
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature, Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature(),
Some(sym::csky_target_feature) => rust_features.csky_target_feature, Some(sym::csky_target_feature) => rust_features.csky_target_feature(),
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature(),
Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature(),
Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature(),
Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86, Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86(),
Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics, Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics(),
Some(sym::xop_target_feature) => rust_features.xop_target_feature, Some(sym::xop_target_feature) => rust_features.xop_target_feature(),
Some(sym::s390x_target_feature) => rust_features.s390x_target_feature, Some(sym::s390x_target_feature) => rust_features.s390x_target_feature(),
Some(name) => bug!("unknown target feature gate {}", name), Some(name) => bug!("unknown target feature gate {}", name),
None => true, None => true,
}; };

View File

@ -611,7 +611,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// the trait into the concrete method, and uses that for const stability // the trait into the concrete method, and uses that for const stability
// checks. // checks.
// FIXME(effects) we might consider moving const stability checks to typeck as well. // FIXME(effects) we might consider moving const stability checks to typeck as well.
if tcx.features().effects { if tcx.features().effects() {
is_trait = true; is_trait = true;
if let Ok(Some(instance)) = if let Ok(Some(instance)) =
@ -631,7 +631,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
args: fn_args, args: fn_args,
span: *fn_span, span: *fn_span,
call_source, call_source,
feature: Some(if tcx.features().const_trait_impl { feature: Some(if tcx.features().const_trait_impl() {
sym::effects sym::effects
} else { } else {
sym::const_trait_impl sym::const_trait_impl

View File

@ -61,7 +61,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
pub fn is_const_stable_const_fn(&self) -> bool { pub fn is_const_stable_const_fn(&self) -> bool {
self.const_kind == Some(hir::ConstContext::ConstFn) self.const_kind == Some(hir::ConstContext::ConstFn)
&& self.tcx.features().staged_api && self.tcx.features().staged_api()
&& is_const_stable_const_fn(self.tcx, self.def_id().to_def_id()) && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id())
} }

View File

@ -24,7 +24,7 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
); );
} }
ccx.tcx.features().const_precise_live_drops ccx.tcx.features().const_precise_live_drops()
} }
/// Look for live drops in a const context. /// Look for live drops in a const context.

View File

@ -88,7 +88,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
// If the enabled feature is stable, record it. // If the enabled feature is stable, record it.
if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
let since = Some(Symbol::intern(f.since)); let since = Some(Symbol::intern(f.since));
features.set_enabled_lang_feature(name, mi.span(), since, None); features.set_enabled_lang_feature(name, mi.span(), since);
continue; continue;
} }
@ -103,7 +103,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
} }
// If the enabled feature is unstable, record it. // If the enabled feature is unstable, record it.
if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) { if UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_some() {
// When the ICE comes from core, alloc or std (approximation of the standard // When the ICE comes from core, alloc or std (approximation of the standard
// library), there's a chance that the person hitting the ICE may be using // library), there's a chance that the person hitting the ICE may be using
// -Zbuild-std or similar with an untested target. The bug is probably in the // -Zbuild-std or similar with an untested target. The bug is probably in the
@ -114,7 +114,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
{ {
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
} }
features.set_enabled_lang_feature(name, mi.span(), None, Some(f)); features.set_enabled_lang_feature(name, mi.span(), None);
continue; continue;
} }
@ -395,7 +395,7 @@ impl<'a> StripUnconfigured<'a> {
/// If attributes are not allowed on expressions, emit an error for `attr` /// If attributes are not allowed on expressions, emit an error for `attr`
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if self.features.is_some_and(|features| !features.stmt_expr_attributes) if self.features.is_some_and(|features| !features.stmt_expr_attributes())
&& !attr.span.allows_unstable(sym::stmt_expr_attributes) && !attr.span.allows_unstable(sym::stmt_expr_attributes)
{ {
let mut err = feature_err( let mut err = feature_err(

View File

@ -867,7 +867,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
| Annotatable::FieldDef(..) | Annotatable::FieldDef(..)
| Annotatable::Variant(..) => panic!("unexpected annotatable"), | Annotatable::Variant(..) => panic!("unexpected annotatable"),
}; };
if self.cx.ecfg.features.proc_macro_hygiene { if self.cx.ecfg.features.proc_macro_hygiene() {
return; return;
} }
feature_err( feature_err(
@ -905,7 +905,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} }
} }
if !self.cx.ecfg.features.proc_macro_hygiene { if !self.cx.ecfg.features.proc_macro_hygiene() {
annotatable.visit_with(&mut GateProcMacroInput { sess: &self.cx.sess }); annotatable.visit_with(&mut GateProcMacroInput { sess: &self.cx.sess });
} }
} }

View File

@ -121,14 +121,14 @@ pub(super) fn parse(
/// Asks for the `macro_metavar_expr` feature if it is not enabled /// Asks for the `macro_metavar_expr` feature if it is not enabled
fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) { fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, span: Span) {
if !features.macro_metavar_expr { if !features.macro_metavar_expr() {
let msg = "meta-variable expressions are unstable"; let msg = "meta-variable expressions are unstable";
feature_err(sess, sym::macro_metavar_expr, span, msg).emit(); feature_err(sess, sym::macro_metavar_expr, span, msg).emit();
} }
} }
fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Session, span: Span) { fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Session, span: Span) {
if !features.macro_metavar_expr_concat { if !features.macro_metavar_expr_concat() {
let msg = "the `concat` meta-variable expression is unstable"; let msg = "the `concat` meta-variable expression is unstable";
feature_err(sess, sym::macro_metavar_expr_concat, span, msg).emit(); feature_err(sess, sym::macro_metavar_expr_concat, span, msg).emit();
} }

View File

@ -14,7 +14,7 @@ type GateFn = fn(&Features) -> bool;
macro_rules! cfg_fn { macro_rules! cfg_fn {
($field: ident) => { ($field: ident) => {
(|features| features.$field) as GateFn Features::$field as GateFn
}; };
} }
@ -1193,7 +1193,7 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>>
pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool { pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool {
match sym { match sym {
sym::on_unimplemented => true, sym::on_unimplemented => true,
sym::do_not_recommend => features.do_not_recommend, sym::do_not_recommend => features.do_not_recommend(),
_ => false, _ => false,
} }
} }

View File

@ -8,7 +8,6 @@ use super::{Feature, to_nonzero};
pub struct UnstableFeature { pub struct UnstableFeature {
pub feature: Feature, pub feature: Feature,
set_enabled: fn(&mut Features),
} }
#[derive(PartialEq)] #[derive(PartialEq)]
@ -30,27 +29,14 @@ macro_rules! status_to_enum {
}; };
} }
macro_rules! declare_features {
($(
$(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr),
)+) => {
/// Unstable language features that are being implemented or being
/// considered for acceptance (stabilization) or removal.
pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[
$(UnstableFeature {
feature: Feature {
name: sym::$feature,
since: $ver,
issue: to_nonzero($issue),
},
// Sets this feature's corresponding bool within `features`.
set_enabled: |features| features.$feature = true,
}),+
];
const NUM_FEATURES: usize = UNSTABLE_FEATURES.len();
/// A set of features to be used by later passes. /// A set of features to be used by later passes.
///
/// There are two ways to check if a language feature `foo` is enabled:
/// - Directly with the `foo` method, e.g. `if tcx.features().foo() { ... }`.
/// - With the `enabled` method, e.g. `if tcx.features.enabled(sym::foo) { ... }`.
///
/// The former is preferred. `enabled` should only be used when the feature symbol is not a
/// constant, e.g. a parameter, or when the feature is a library feature.
#[derive(Clone, Default, Debug)] #[derive(Clone, Default, Debug)]
pub struct Features { pub struct Features {
/// `#![feature]` attrs for language features, for error reporting. /// `#![feature]` attrs for language features, for error reporting.
@ -59,48 +45,17 @@ macro_rules! declare_features {
enabled_lib_features: Vec<(Symbol, Span)>, enabled_lib_features: Vec<(Symbol, Span)>,
/// `enabled_lang_features` + `enabled_lib_features`. /// `enabled_lang_features` + `enabled_lib_features`.
enabled_features: FxHashSet<Symbol>, enabled_features: FxHashSet<Symbol>,
/// State of individual features (unstable lang features only).
/// This is `true` if and only if the corresponding feature is listed in `enabled_lang_features`.
$(
$(#[doc = $doc])*
pub $feature: bool
),+
} }
impl Features { impl Features {
pub fn set_enabled_lang_feature( pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option<Symbol>) {
&mut self,
name: Symbol,
span: Span,
since: Option<Symbol>,
feature: Option<&UnstableFeature>,
) {
self.enabled_lang_features.push((name, span, since)); self.enabled_lang_features.push((name, span, since));
self.enabled_features.insert(name); self.enabled_features.insert(name);
if let Some(feature) = feature {
assert_eq!(feature.feature.name, name);
(feature.set_enabled)(self);
} else {
// Ensure we don't skip a `set_enabled` call.
debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none());
}
} }
pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) { pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) {
self.enabled_lib_features.push((name, span)); self.enabled_lib_features.push((name, span));
self.enabled_features.insert(name); self.enabled_features.insert(name);
// Ensure we don't skip a `set_enabled` call.
debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none());
}
/// This is intended for hashing the set of enabled 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_lang_features(&self) -> [u8; NUM_FEATURES] {
[$(self.$feature as u8),+]
} }
pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> { pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> {
@ -117,23 +72,32 @@ macro_rules! declare_features {
/// Is the given feature enabled (via `#[feature(...)]`)? /// Is the given feature enabled (via `#[feature(...)]`)?
pub fn enabled(&self, feature: Symbol) -> bool { pub fn enabled(&self, feature: Symbol) -> bool {
let e = self.enabled_features.contains(&feature); self.enabled_features.contains(&feature)
if cfg!(debug_assertions) {
// Ensure this matches `self.$feature`, if that exists.
let e2 = match feature {
$( sym::$feature => Some(self.$feature), )*
_ => None,
};
if let Some(e2) = e2 {
assert_eq!(
e, e2,
"mismatch in feature state for `{feature}`: \
`enabled_features` says {e} but `self.{feature}` says {e2}"
);
} }
} }
e
macro_rules! declare_features {
($(
$(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr),
)+) => {
/// Unstable language features that are being implemented or being
/// considered for acceptance (stabilization) or removal.
pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[
$(UnstableFeature {
feature: Feature {
name: sym::$feature,
since: $ver,
issue: to_nonzero($issue),
},
}),+
];
impl Features {
$(
pub fn $feature(&self) -> bool {
self.enabled_features.contains(&sym::$feature)
} }
)*
/// Some features are known to be incomplete and using them is likely to have /// Some features are known to be incomplete and using them is likely to have
/// unanticipated results, such as compiler crashes. We warn the user about these /// unanticipated results, such as compiler crashes. We warn the user about these

View File

@ -72,7 +72,7 @@ impl<'tcx> Bounds<'tcx> {
// FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else.
// Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated
// type bounds. // type bounds.
if !tcx.features().effects { if !tcx.features().effects() {
return; return;
} }
match predicate_filter { match predicate_filter {

View File

@ -1166,7 +1166,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
return; return;
} }
if adt.is_union() && !tcx.features().transparent_unions { if adt.is_union() && !tcx.features().transparent_unions() {
feature_err( feature_err(
&tcx.sess, &tcx.sess,
sym::transparent_unions, sym::transparent_unions,
@ -1301,7 +1301,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let repr_type_ty = def.repr().discr_type().to_ty(tcx); let repr_type_ty = def.repr().discr_type().to_ty(tcx);
if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
if !tcx.features().repr128 { if !tcx.features().repr128() {
feature_err( feature_err(
&tcx.sess, &tcx.sess,
sym::repr128, sym::repr128,

View File

@ -167,7 +167,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
} }
} }
if let Some(tail_expr) = blk.expr { if let Some(tail_expr) = blk.expr {
if visitor.tcx.features().shorter_tail_lifetimes if visitor.tcx.features().shorter_tail_lifetimes()
&& blk.span.edition().at_least_rust_2024() && blk.span.edition().at_least_rust_2024()
{ {
visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); visitor.terminating_scopes.insert(tail_expr.hir_id.local_id);
@ -466,7 +466,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
hir::ExprKind::If(cond, then, Some(otherwise)) => { hir::ExprKind::If(cond, then, Some(otherwise)) => {
let expr_cx = visitor.cx; let expr_cx = visitor.cx;
let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope()
{
ScopeData::IfThenRescope ScopeData::IfThenRescope
} else { } else {
ScopeData::IfThen ScopeData::IfThen
@ -481,7 +482,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
hir::ExprKind::If(cond, then, None) => { hir::ExprKind::If(cond, then, None) => {
let expr_cx = visitor.cx; let expr_cx = visitor.cx;
let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope()
{
ScopeData::IfThenRescope ScopeData::IfThenRescope
} else { } else {
ScopeData::IfThen ScopeData::IfThen

View File

@ -110,7 +110,7 @@ where
let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env };
if !tcx.features().trivial_bounds { if !tcx.features().trivial_bounds() {
wfcx.check_false_global_bounds() wfcx.check_false_global_bounds()
} }
f(&mut wfcx)?; f(&mut wfcx)?;
@ -921,7 +921,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
} => { } => {
let ty = tcx.type_of(param.def_id).instantiate_identity(); let ty = tcx.type_of(param.def_id).instantiate_identity();
if tcx.features().unsized_const_params { if tcx.features().unsized_const_params() {
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
wfcx.register_bound( wfcx.register_bound(
ObligationCause::new( ObligationCause::new(
@ -935,7 +935,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
); );
Ok(()) Ok(())
}) })
} else if tcx.features().adt_const_params { } else if tcx.features().adt_const_params() {
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
wfcx.register_bound( wfcx.register_bound(
ObligationCause::new( ObligationCause::new(
@ -1698,9 +1698,9 @@ fn check_method_receiver<'tcx>(
return Ok(()); return Ok(());
} }
let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers { let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers() {
Some(ArbitrarySelfTypesLevel::WithPointers) Some(ArbitrarySelfTypesLevel::WithPointers)
} else if tcx.features().arbitrary_self_types { } else if tcx.features().arbitrary_self_types() {
Some(ArbitrarySelfTypesLevel::Basic) Some(ArbitrarySelfTypesLevel::Basic)
} else { } else {
None None

View File

@ -77,7 +77,7 @@ impl<'tcx> InherentCollect<'tcx> {
return Ok(()); return Ok(());
} }
if self.tcx.features().rustc_attrs { if self.tcx.features().rustc_attrs() {
let items = self.tcx.associated_item_def_ids(impl_def_id); let items = self.tcx.associated_item_def_ids(impl_def_id);
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
@ -115,7 +115,7 @@ impl<'tcx> InherentCollect<'tcx> {
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let items = self.tcx.associated_item_def_ids(impl_def_id); let items = self.tcx.associated_item_def_ids(impl_def_id);
if !self.tcx.hir().rustc_coherence_is_core() { if !self.tcx.hir().rustc_coherence_is_core() {
if self.tcx.features().rustc_attrs { if self.tcx.features().rustc_attrs() {
for &impl_item in items { for &impl_item in items {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let span = self.tcx.def_span(impl_def_id); let span = self.tcx.def_span(impl_def_id);

View File

@ -53,7 +53,7 @@ fn enforce_trait_manually_implementable(
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let impl_header_span = tcx.def_span(impl_def_id); let impl_header_span = tcx.def_span(impl_def_id);
if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls { if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls() {
feature_err( feature_err(
&tcx.sess, &tcx.sess,
sym::freeze_impls, sym::freeze_impls,
@ -86,8 +86,8 @@ fn enforce_trait_manually_implementable(
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind
{ {
if !tcx.features().specialization if !tcx.features().specialization()
&& !tcx.features().min_specialization && !tcx.features().min_specialization()
&& !impl_header_span.allows_unstable(sym::specialization) && !impl_header_span.allows_unstable(sym::specialization)
&& !impl_header_span.allows_unstable(sym::min_specialization) && !impl_header_span.allows_unstable(sym::min_specialization)
{ {

View File

@ -1129,7 +1129,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
}; };
let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
if paren_sugar && !tcx.features().unboxed_closures { if paren_sugar && !tcx.features().unboxed_closures() {
tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span }); tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
} }
@ -1696,7 +1696,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
// Feature gate SIMD types in FFI, since I am not sure that the // Feature gate SIMD types in FFI, since I am not sure that the
// ABIs are handled at all correctly. -huonw // ABIs are handled at all correctly. -huonw
if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi { if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi() {
let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| { let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| {
if ty.is_simd() { if ty.is_simd() {
let snip = tcx let snip = tcx

View File

@ -109,7 +109,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// We do not allow generic parameters in anon consts if we are inside // We do not allow generic parameters in anon consts if we are inside
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed. // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None None
} else if tcx.features().generic_const_exprs { } else if tcx.features().generic_const_exprs() {
let parent_node = tcx.parent_hir_node(hir_id); let parent_node = tcx.parent_hir_node(hir_id);
debug!(?parent_node); debug!(?parent_node);
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node

View File

@ -308,7 +308,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
} }
} }
if tcx.features().generic_const_exprs { if tcx.features().generic_const_exprs() {
predicates.extend(const_evaluatable_predicates_of(tcx, def_id)); predicates.extend(const_evaluatable_predicates_of(tcx, def_id));
} }
@ -524,7 +524,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
} }
} else { } else {
if matches!(def_kind, DefKind::AnonConst) if matches!(def_kind, DefKind::AnonConst)
&& tcx.features().generic_const_exprs && tcx.features().generic_const_exprs()
&& let Some(defaulted_param_def_id) = && let Some(defaulted_param_def_id) =
tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id)) tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id))
{ {

View File

@ -1161,7 +1161,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
&& param.is_elided_lifetime() && param.is_elided_lifetime()
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
&& !self.tcx.features().anonymous_lifetime_in_impl_trait && !self.tcx.features().anonymous_lifetime_in_impl_trait()
{ {
let mut diag: rustc_errors::Diag<'_> = rustc_session::parse::feature_err( let mut diag: rustc_errors::Diag<'_> = rustc_session::parse::feature_err(
&self.tcx.sess, &self.tcx.sess,
@ -2239,7 +2239,7 @@ fn deny_non_region_late_bound(
format!("late-bound {what} parameter not allowed on {where_}"), format!("late-bound {what} parameter not allowed on {where_}"),
); );
let guar = diag.emit_unless(!tcx.features().non_lifetime_binders || !first); let guar = diag.emit_unless(!tcx.features().non_lifetime_binders() || !first);
first = false; first = false;
*arg = ResolvedArg::Error(guar); *arg = ResolvedArg::Error(guar);

View File

@ -699,7 +699,7 @@ fn infer_placeholder_type<'tcx>(
} }
fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
if !tcx.features().inherent_associated_types { if !tcx.features().inherent_associated_types() {
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
feature_err( feature_err(
@ -714,7 +714,7 @@ fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
use hir::intravisit::Visitor; use hir::intravisit::Visitor;
if tcx.features().lazy_type_alias { if tcx.features().lazy_type_alias() {
return true; return true;
} }
struct HasTait; struct HasTait;

View File

@ -88,7 +88,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}; };
if seen_repeat { if seen_repeat {
self.dcx().emit_err(err); self.dcx().emit_err(err);
} else if !tcx.features().more_maybe_bounds { } else if !tcx.features().more_maybe_bounds() {
self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit(); self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit();
}; };
} }

View File

@ -63,7 +63,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_segment: &'_ hir::PathSegment<'_>, trait_segment: &'_ hir::PathSegment<'_>,
is_impl: bool, is_impl: bool,
) { ) {
if self.tcx().features().unboxed_closures { if self.tcx().features().unboxed_closures() {
return; return;
} }
@ -343,7 +343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&& let Some(hir_ty) = constraint.ty() && let Some(hir_ty) = constraint.ty()
&& let ty = self.lower_ty(hir_ty) && let ty = self.lower_ty(hir_ty)
&& (ty.is_enum() || ty.references_error()) && (ty.is_enum() || ty.references_error())
&& tcx.features().associated_const_equality && tcx.features().associated_const_equality()
{ {
Some(errors::AssocKindMismatchWrapInBracesSugg { Some(errors::AssocKindMismatchWrapInBracesSugg {
lo: hir_ty.span.shrink_to_lo(), lo: hir_ty.span.shrink_to_lo(),

View File

@ -1241,7 +1241,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
// errors (#108491) which mask the feature-gate error, needlessly confusing users // errors (#108491) which mask the feature-gate error, needlessly confusing users
// who use IATs by accident (#113265). // who use IATs by accident (#113265).
if !tcx.features().inherent_associated_types { if !tcx.features().inherent_associated_types() {
return Ok(None); return Ok(None);
} }

View File

@ -57,7 +57,7 @@ pub(crate) fn check_impl_wf(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
impl_def_id: LocalDefId, impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let min_specialization = tcx.features().min_specialization; let min_specialization = tcx.features().min_specialization();
let mut res = Ok(()); let mut res = Ok(());
debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. }); debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id)); res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id));

View File

@ -116,7 +116,7 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
return; return;
} }
let extended_abi_support = tcx.features().extended_varargs_abi_support; let extended_abi_support = tcx.features().extended_varargs_abi_support();
let conventions = match (extended_abi_support, abi.supports_varargs()) { let conventions = match (extended_abi_support, abi.supports_varargs()) {
// User enabled additional ABI support for varargs and function ABI matches those ones. // User enabled additional ABI support for varargs and function ABI matches those ones.
(true, true) => return, (true, true) => return,
@ -155,7 +155,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
// FIXME(effects): remove once effects is implemented in old trait solver // FIXME(effects): remove once effects is implemented in old trait solver
// or if the next solver is stabilized. // or if the next solver is stabilized.
if tcx.features().effects && !tcx.next_trait_solver_globally() { if tcx.features().effects() && !tcx.next_trait_solver_globally() {
tcx.dcx().emit_err(errors::EffectsWithoutNextSolver); tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
} }
@ -172,7 +172,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); let _ = tcx.ensure().crate_inherent_impls_overlap_check(());
}); });
if tcx.features().rustc_attrs { if tcx.features().rustc_attrs() {
tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx)); tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx));
tcx.sess.time("variance_dumping", || variance::dump::variances(tcx)); tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
collect::dump::opaque_hidden_types(tcx); collect::dump::opaque_hidden_types(tcx);

View File

@ -23,7 +23,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
let crate_map = tcx.inferred_outlives_crate(()); let crate_map = tcx.inferred_outlives_crate(());
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]) crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
} }
DefKind::AnonConst if tcx.features().generic_const_exprs => { DefKind::AnonConst if tcx.features().generic_const_exprs() => {
let id = tcx.local_def_id_to_hir_id(item_def_id); let id = tcx.local_def_id_to_hir_id(item_def_id);
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() { if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
// In `generics_of` we set the generics' parent to be our parent's parent which means that // In `generics_of` we set the generics' parent to be our parent's parent which means that

View File

@ -721,7 +721,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
use rustc_middle::ty::cast::IntTy::*; use rustc_middle::ty::cast::IntTy::*;
if self.cast_ty.is_dyn_star() { if self.cast_ty.is_dyn_star() {
if fcx.tcx.features().dyn_star { if fcx.tcx.features().dyn_star() {
span_bug!(self.span, "should be handled by `coerce`"); span_bug!(self.span, "should be handled by `coerce`");
} else { } else {
// Report "casting is invalid" rather than "non-primitive cast" // Report "casting is invalid" rather than "non-primitive cast"

View File

@ -223,11 +223,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
ty::Ref(r_b, _, mutbl_b) => { ty::Ref(r_b, _, mutbl_b) => {
return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
} }
ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => { ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star() => {
return self.coerce_dyn_star(a, b, predicates, region); return self.coerce_dyn_star(a, b, predicates, region);
} }
ty::Adt(pin, _) ty::Adt(pin, _)
if self.tcx.features().pin_ergonomics if self.tcx.features().pin_ergonomics()
&& self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => && self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) =>
{ {
return self.coerce_pin(a, b); return self.coerce_pin(a, b);
@ -698,7 +698,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
} }
if let Some((sub, sup)) = has_trait_upcasting_coercion if let Some((sub, sup)) = has_trait_upcasting_coercion
&& !self.tcx().features().trait_upcasting && !self.tcx().features().trait_upcasting()
{ {
// Renders better when we erase regions, since they're not really the point here. // Renders better when we erase regions, since they're not really the point here.
let (sub, sup) = self.tcx.erase_regions((sub, sup)); let (sub, sup) = self.tcx.erase_regions((sub, sup));
@ -712,7 +712,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
err.emit(); err.emit();
} }
if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() {
feature_err( feature_err(
&self.tcx.sess, &self.tcx.sess,
sym::unsized_tuple_coercion, sym::unsized_tuple_coercion,
@ -732,7 +732,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
b_region: ty::Region<'tcx>, b_region: ty::Region<'tcx>,
) -> CoerceResult<'tcx> { ) -> CoerceResult<'tcx> {
if !self.tcx.features().dyn_star { if !self.tcx.features().dyn_star() {
return Err(TypeError::Mismatch); return Err(TypeError::Mismatch);
} }
@ -1695,7 +1695,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
blk_id, blk_id,
expression, expression,
); );
if !fcx.tcx.features().unsized_locals { if !fcx.tcx.features().unsized_locals() {
unsized_return = self.is_return_ty_definitely_unsized(fcx); unsized_return = self.is_return_ty_definitely_unsized(fcx);
} }
} }
@ -1709,7 +1709,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
return_expr_id, return_expr_id,
expression, expression,
); );
if !fcx.tcx.features().unsized_locals { if !fcx.tcx.features().unsized_locals() {
unsized_return = self.is_return_ty_definitely_unsized(fcx); unsized_return = self.is_return_ty_definitely_unsized(fcx);
} }
} }

View File

@ -735,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// be known if explicitly specified via turbofish). // be known if explicitly specified via turbofish).
self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id));
} }
if !tcx.features().unsized_fn_params { if !tcx.features().unsized_fn_params() {
// We want to remove some Sized bounds from std functions, // We want to remove some Sized bounds from std functions,
// but don't want to expose the removal to stable Rust. // but don't want to expose the removal to stable Rust.
// i.e., we don't want to allow // i.e., we don't want to allow
@ -1996,7 +1996,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(base_expr) = base_expr { if let Some(base_expr) = base_expr {
// FIXME: We are currently creating two branches here in order to maintain // FIXME: We are currently creating two branches here in order to maintain
// consistency. But they should be merged as much as possible. // consistency. But they should be merged as much as possible.
let fru_tys = if self.tcx.features().type_changing_struct_update { let fru_tys = if self.tcx.features().type_changing_struct_update() {
if adt.is_struct() { if adt.is_struct() {
// Make some fresh generic parameters for our ADT type. // Make some fresh generic parameters for our ADT type.
let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did()); let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did());
@ -3552,7 +3552,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (ident, _def_scope) = let (ident, _def_scope) =
self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
if !self.tcx.features().offset_of_enum { if !self.tcx.features().offset_of_enum() {
rustc_session::parse::feature_err( rustc_session::parse::feature_err(
&self.tcx.sess, &self.tcx.sess,
sym::offset_of_enum, sym::offset_of_enum,
@ -3642,7 +3642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
let field_ty = self.field_ty(expr.span, field, args); let field_ty = self.field_ty(expr.span, field, args);
if self.tcx.features().offset_of_slice { if self.tcx.features().offset_of_slice() {
self.require_type_has_static_alignment( self.require_type_has_static_alignment(
field_ty, field_ty,
expr.span, expr.span,
@ -3675,7 +3675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& field.name == sym::integer(index) && field.name == sym::integer(index)
{ {
if let Some(&field_ty) = tys.get(index) { if let Some(&field_ty) = tys.get(index) {
if self.tcx.features().offset_of_slice { if self.tcx.features().offset_of_slice() {
self.require_type_has_static_alignment( self.require_type_has_static_alignment(
field_ty, field_ty,
expr.span, expr.span,

View File

@ -1486,7 +1486,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return ty::Const::new_error(self.tcx, guar); return ty::Const::new_error(self.tcx, guar);
} }
} }
} else if self.tcx.features().generic_const_exprs { } else if self.tcx.features().generic_const_exprs() {
ct.normalize_internal(self.tcx, self.param_env) ct.normalize_internal(self.tcx, self.param_env)
} else { } else {
ct ct

View File

@ -404,7 +404,7 @@ fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
} }
// `feature(never_type_fallback)`: fallback to `!` or `()` trying to not break stuff // `feature(never_type_fallback)`: fallback to `!` or `()` trying to not break stuff
if tcx.features().never_type_fallback { if tcx.features().never_type_fallback() {
return DivergingFallbackBehavior::ContextDependent; return DivergingFallbackBehavior::ContextDependent;
} }

View File

@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
let var_ty = self.assign(p.span, p.hir_id, None); let var_ty = self.assign(p.span, p.hir_id, None);
if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat { if let Some((ty_span, hir_id)) = self.outermost_fn_param_pat {
if !self.fcx.tcx.features().unsized_fn_params { if !self.fcx.tcx.features().unsized_fn_params() {
self.fcx.require_type_is_sized( self.fcx.require_type_is_sized(
var_ty, var_ty,
ty_span, ty_span,
@ -158,7 +158,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
), ),
); );
} }
} else if !self.fcx.tcx.features().unsized_locals { } else if !self.fcx.tcx.features().unsized_locals() {
self.fcx.require_type_is_sized( self.fcx.require_type_is_sized(
var_ty, var_ty,
p.span, p.span,

View File

@ -161,7 +161,7 @@ fn typeck_with_fallback<'tcx>(
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
let fn_sig = fcx.normalize(body.value.span, fn_sig); let fn_sig = fcx.normalize(body.value.span, fn_sig);
check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params); check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params());
} else { } else {
let expected_type = infer_type_if_missing(&fcx, node); let expected_type = infer_type_if_missing(&fcx, node);
let expected_type = expected_type.unwrap_or_else(fallback); let expected_type = expected_type.unwrap_or_else(fallback);

View File

@ -536,7 +536,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// FIXME(arbitrary_self_types): We probably should limit the // FIXME(arbitrary_self_types): We probably should limit the
// situations where this can occur by adding additional restrictions // situations where this can occur by adding additional restrictions
// to the feature, like the self type can't reference method args. // to the feature, like the self type can't reference method args.
if self.tcx.features().arbitrary_self_types { if self.tcx.features().arbitrary_self_types() {
self.err_ctxt() self.err_ctxt()
.report_mismatched_types(&cause, method_self_ty, self_ty, terr) .report_mismatched_types(&cause, method_self_ty, self_ty, terr)
.emit(); .emit();

View File

@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mode, mode,
})); }));
} else if bad_ty.reached_raw_pointer } else if bad_ty.reached_raw_pointer
&& !self.tcx.features().arbitrary_self_types_pointers && !self.tcx.features().arbitrary_self_types_pointers()
&& !self.tcx.sess.at_least_rust_2018() && !self.tcx.sess.at_least_rust_2018()
{ {
// this case used to be allowed by the compiler, // this case used to be allowed by the compiler,
@ -429,8 +429,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.resolve_vars_if_possible(ty.value); let ty = self.resolve_vars_if_possible(ty.value);
let guar = match *ty.kind() { let guar = match *ty.kind() {
ty::Infer(ty::TyVar(_)) => { ty::Infer(ty::TyVar(_)) => {
let raw_ptr_call = let raw_ptr_call = bad_ty.reached_raw_pointer
bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types; && !self.tcx.features().arbitrary_self_types();
let mut err = self.err_ctxt().emit_inference_failure_err( let mut err = self.err_ctxt().emit_inference_failure_err(
self.body_id, self.body_id,
span, span,
@ -1146,7 +1146,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
} }
ty::Adt(def, args) ty::Adt(def, args)
if self.tcx.features().pin_ergonomics if self.tcx.features().pin_ergonomics()
&& self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) => && self.tcx.is_lang_item(def.did(), hir::LangItem::Pin) =>
{ {
// make sure this is a pinned reference (and not a `Pin<Box>` or something) // make sure this is a pinned reference (and not a `Pin<Box>` or something)
@ -1195,7 +1195,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> { ) -> Option<PickResult<'tcx>> {
if !self.tcx.features().pin_ergonomics { if !self.tcx.features().pin_ergonomics() {
return None; return None;
} }

View File

@ -442,7 +442,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
let features = self.tcx.features(); let features = self.tcx.features();
if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural { if features.ref_pat_eat_one_layer_2024() || features.ref_pat_eat_one_layer_2024_structural()
{
def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
if def_br == ByRef::Yes(Mutability::Not) { if def_br == ByRef::Yes(Mutability::Not) {
max_ref_mutbl = MutblCap::Not; max_ref_mutbl = MutblCap::Not;
@ -490,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
if self.tcx.features().string_deref_patterns if self.tcx.features().string_deref_patterns()
&& let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind
{ {
let tcx = self.tcx; let tcx = self.tcx;
@ -675,10 +676,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let bm = match user_bind_annot { let bm = match user_bind_annot {
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
if pat.span.at_least_rust_2024() if pat.span.at_least_rust_2024()
&& (self.tcx.features().ref_pat_eat_one_layer_2024 && (self.tcx.features().ref_pat_eat_one_layer_2024()
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural) || self.tcx.features().ref_pat_eat_one_layer_2024_structural())
{ {
if !self.tcx.features().mut_ref { if !self.tcx.features().mut_ref() {
feature_err( feature_err(
&self.tcx.sess, &self.tcx.sess,
sym::mut_ref, sym::mut_ref,
@ -2152,8 +2153,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let features = tcx.features(); let features = tcx.features();
let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024; let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024();
let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural; let ref_pat_eat_one_layer_2024_structural =
features.ref_pat_eat_one_layer_2024_structural();
let no_ref_mut_behind_and = let no_ref_mut_behind_and =
ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural; ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural;

View File

@ -488,7 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let final_upvar_tys = self.final_upvar_tys(closure_def_id); let final_upvar_tys = self.final_upvar_tys(closure_def_id);
debug!(?closure_hir_id, ?args, ?final_upvar_tys); debug!(?closure_hir_id, ?args, ?final_upvar_tys);
if self.tcx.features().unsized_locals || self.tcx.features().unsized_fn_params { if self.tcx.features().unsized_locals() || self.tcx.features().unsized_fn_params() {
for capture in for capture in
self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id) self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id)
{ {

View File

@ -830,7 +830,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
value = tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased); value = tcx.fold_regions(value, |_, _| tcx.lifetimes.re_erased);
// Normalize consts in writeback, because GCE doesn't normalize eagerly. // Normalize consts in writeback, because GCE doesn't normalize eagerly.
if tcx.features().generic_const_exprs { if tcx.features().generic_const_exprs() {
value = value =
value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env }); value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env });
} }

View File

@ -68,7 +68,7 @@ pub(crate) fn assert_dep_graph(tcx: TyCtxt<'_>) {
// if the `rustc_attrs` feature is not enabled, then the // if the `rustc_attrs` feature is not enabled, then the
// attributes we are interested in cannot be present anyway, so // attributes we are interested in cannot be present anyway, so
// skip the walk. // skip the walk.
if !tcx.features().rustc_attrs { if !tcx.features().rustc_attrs() {
return; return;
} }

View File

@ -140,7 +140,7 @@ pub(crate) fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
} }
// can't add `#[rustc_clean]` etc without opting into this feature // can't add `#[rustc_clean]` etc without opting into this feature
if !tcx.features().rustc_attrs { if !tcx.features().rustc_attrs() {
return; return;
} }

View File

@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
&& let hir::IsAsync::Async(async_span) = sig.header.asyncness && let hir::IsAsync::Async(async_span) = sig.header.asyncness
{ {
// RTN can be used to bound `async fn` in traits in a better way than "always" // RTN can be used to bound `async fn` in traits in a better way than "always"
if cx.tcx.features().return_type_notation { if cx.tcx.features().return_type_notation() {
return; return;
} }

View File

@ -1235,7 +1235,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
def_id: LocalDefId, def_id: LocalDefId,
) { ) {
if fn_kind.asyncness().is_async() if fn_kind.asyncness().is_async()
&& !cx.tcx.features().async_fn_track_caller && !cx.tcx.features().async_fn_track_caller()
// Now, check if the function has the `#[track_caller]` attribute // Now, check if the function has the `#[track_caller]` attribute
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
{ {
@ -1424,7 +1424,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
// See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`. // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`.
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)
&& cx.tcx.features().generic_const_exprs && cx.tcx.features().generic_const_exprs()
{ {
return; return;
} }
@ -1538,7 +1538,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::ClauseKind; use rustc_middle::ty::ClauseKind;
if cx.tcx.features().trivial_bounds { if cx.tcx.features().trivial_bounds() {
let predicates = cx.tcx.predicates_of(item.owner_id); let predicates = cx.tcx.predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates { for &(predicate, span) in predicates.predicates {
let predicate_kind_name = match predicate.kind().skip_binder() { let predicate_kind_name = match predicate.kind().skip_binder() {

View File

@ -243,7 +243,7 @@ impl_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for IfLetRescope { impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope { if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope() {
return; return;
} }
if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {

View File

@ -263,8 +263,8 @@ where
&& parent == self.parent_def_id && parent == self.parent_def_id
{ {
let opaque_span = self.tcx.def_span(opaque_def_id); let opaque_span = self.tcx.def_span(opaque_def_id);
let new_capture_rules = let new_capture_rules = opaque_span.at_least_rust_2024()
opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024; || self.tcx.features().lifetime_capture_rules_2024();
if !new_capture_rules if !new_capture_rules
&& !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
{ {

View File

@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder {
_: Span, _: Span,
def_id: rustc_span::def_id::LocalDefId, def_id: rustc_span::def_id::LocalDefId,
) { ) {
if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes { if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes() {
Self::check_fn_or_closure(cx, fn_kind, body, def_id); Self::check_fn_or_closure(cx, fn_kind, body, def_id);
} }
} }

View File

@ -170,7 +170,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
let mut upstream_in_dylibs = FxHashSet::default(); let mut upstream_in_dylibs = FxHashSet::default();
if tcx.features().rustc_private { if tcx.features().rustc_private() {
// We need this to prevent users of `rustc_driver` from linking dynamically to `std` // We need this to prevent users of `rustc_driver` from linking dynamically to `std`
// which does not work as `std` is also statically linked into `rustc_driver`. // which does not work as `std` is also statically linked into `rustc_driver`.

View File

@ -265,7 +265,7 @@ impl<'tcx> Collector<'tcx> {
NativeLibKind::RawDylib NativeLibKind::RawDylib
} }
"link-arg" => { "link-arg" => {
if !features.link_arg_attribute { if !features.link_arg_attribute() {
feature_err( feature_err(
sess, sess,
sym::link_arg_attribute, sym::link_arg_attribute,
@ -314,7 +314,7 @@ impl<'tcx> Collector<'tcx> {
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue; continue;
}; };
if !features.link_cfg { if !features.link_cfg() {
feature_err( feature_err(
sess, sess,
sym::link_cfg, sym::link_cfg,
@ -384,7 +384,7 @@ impl<'tcx> Collector<'tcx> {
}; };
macro report_unstable_modifier($feature: ident) { macro report_unstable_modifier($feature: ident) {
if !features.$feature { if !features.$feature() {
// FIXME: make this translatable // FIXME: make this translatable
#[expect(rustc::untranslatable_diagnostic)] #[expect(rustc::untranslatable_diagnostic)]
feature_err( feature_err(

View File

@ -1765,7 +1765,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_stability(&mut self, def_id: DefId) { fn encode_stability(&mut self, def_id: DefId) {
// The query lookup can take a measurable amount of time in crates with many items. Check if // The query lookup can take a measurable amount of time in crates with many items. Check if
// the stability attributes are even enabled before using their queries. // the stability attributes are even enabled before using their queries.
if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
if let Some(stab) = self.tcx.lookup_stability(def_id) { if let Some(stab) = self.tcx.lookup_stability(def_id) {
record!(self.tables.lookup_stability[def_id] <- stab) record!(self.tables.lookup_stability[def_id] <- stab)
} }
@ -1776,7 +1776,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_const_stability(&mut self, def_id: DefId) { fn encode_const_stability(&mut self, def_id: DefId) {
// The query lookup can take a measurable amount of time in crates with many items. Check if // The query lookup can take a measurable amount of time in crates with many items. Check if
// the stability attributes are even enabled before using their queries. // the stability attributes are even enabled before using their queries.
if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
if let Some(stab) = self.tcx.lookup_const_stability(def_id) { if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
record!(self.tables.lookup_const_stability[def_id] <- stab) record!(self.tables.lookup_const_stability[def_id] <- stab)
} }
@ -1787,7 +1787,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_default_body_stability(&mut self, def_id: DefId) { fn encode_default_body_stability(&mut self, def_id: DefId) {
// The query lookup can take a measurable amount of time in crates with many items. Check if // The query lookup can take a measurable amount of time in crates with many items. Check if
// the stability attributes are even enabled before using their queries. // the stability attributes are even enabled before using their queries.
if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { if self.feat.staged_api() || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) { if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
record!(self.tables.lookup_default_body_stability[def_id] <- stab) record!(self.tables.lookup_default_body_stability[def_id] <- stab)
} }

View File

@ -116,7 +116,7 @@ impl<'tcx> TyCtxt<'tcx> {
// @lcnr believes that successfully evaluating even though there are // @lcnr believes that successfully evaluating even though there are
// used generic parameters is a bug of evaluation, so checking for it // used generic parameters is a bug of evaluation, so checking for it
// here does feel somewhat sensible. // here does feel somewhat sensible.
if !self.features().generic_const_exprs && ct.args.has_non_region_param() { if !self.features().generic_const_exprs() && ct.args.has_non_region_param() {
let def_kind = self.def_kind(instance.def_id()); let def_kind = self.def_kind(instance.def_id());
assert!( assert!(
matches!( matches!(

View File

@ -61,7 +61,7 @@ pub enum OverlapMode {
impl OverlapMode { impl OverlapMode {
pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode { pub fn get(tcx: TyCtxt<'_>, trait_id: DefId) -> OverlapMode {
let with_negative_coherence = tcx.features().with_negative_coherence; let with_negative_coherence = tcx.features().with_negative_coherence();
let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence); let strict_coherence = tcx.has_attr(trait_id, sym::rustc_strict_coherence);
if with_negative_coherence { if with_negative_coherence {

View File

@ -710,15 +710,15 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features { impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features {
fn generic_const_exprs(self) -> bool { fn generic_const_exprs(self) -> bool {
self.generic_const_exprs self.generic_const_exprs()
} }
fn coroutine_clone(self) -> bool { fn coroutine_clone(self) -> bool {
self.coroutine_clone self.coroutine_clone()
} }
fn associated_const_equality(self) -> bool { fn associated_const_equality(self) -> bool {
self.associated_const_equality self.associated_const_equality()
} }
} }

View File

@ -398,7 +398,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
), ),
} }
} }
ty::Array(inner, len) if tcx.features().transmute_generic_consts => { ty::Array(inner, len) if tcx.features().transmute_generic_consts() => {
let len_eval = len.try_to_target_usize(tcx); let len_eval = len.try_to_target_usize(tcx);
if len_eval == Some(0) { if len_eval == Some(0) {
return Ok(SizeSkeleton::Known(Size::from_bytes(0), None)); return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));

View File

@ -1208,7 +1208,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
} }
} }
if self.tcx().features().return_type_notation if self.tcx().features().return_type_notation()
&& let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
self.tcx().opt_rpitit_info(def_id) self.tcx().opt_rpitit_info(def_id)
&& let ty::Alias(_, alias_ty) = && let ty::Alias(_, alias_ty) =

View File

@ -750,7 +750,7 @@ impl<'tcx> Ty<'tcx> {
#[inline] #[inline]
pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
if tcx.features().never_type_fallback { tcx.types.never } else { tcx.types.unit } if tcx.features().never_type_fallback() { tcx.types.never } else { tcx.types.unit }
} }
// lang and diagnostic tys // lang and diagnostic tys

View File

@ -877,8 +877,8 @@ impl<'tcx> TyCtxt<'tcx> {
// FIXME(effects): This is suspicious and should probably not be done, // FIXME(effects): This is suspicious and should probably not be done,
// especially now that we enforce host effects and then properly handle // especially now that we enforce host effects and then properly handle
// effect vars during fallback. // effect vars during fallback.
let mut host_always_on = let mut host_always_on = !self.features().effects()
!self.features().effects || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you;
// Compute the constness required by the context. // Compute the constness required by the context.
let const_context = self.hir().body_const_context(def_id); let const_context = self.hir().body_const_context(def_id);
@ -1826,8 +1826,8 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
/// cause an ICE that we otherwise may want to prevent. /// cause an ICE that we otherwise may want to prevent.
pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> { pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> {
if (matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic) if (matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic)
&& tcx.features().intrinsics) && tcx.features().intrinsics())
|| (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs) || (tcx.has_attr(def_id, sym::rustc_intrinsic) && tcx.features().rustc_attrs())
{ {
Some(ty::IntrinsicDef { Some(ty::IntrinsicDef {
name: tcx.item_name(def_id.into()), name: tcx.item_name(def_id.into()),

View File

@ -163,7 +163,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let tcx = this.tcx; let tcx = this.tcx;
if tcx.features().unsized_fn_params { if tcx.features().unsized_fn_params() {
let ty = expr.ty; let ty = expr.ty;
let param_env = this.param_env; let param_env = this.param_env;

View File

@ -149,7 +149,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let ty::Adt(def, _) = ty.kind() if let ty::Adt(def, _) = ty.kind()
&& tcx.is_lang_item(def.did(), LangItem::String) && tcx.is_lang_item(def.did(), LangItem::String)
{ {
if !tcx.features().string_deref_patterns { if !tcx.features().string_deref_patterns() {
span_bug!( span_bug!(
test.span, test.span,
"matching on `String` went through without enabling string_deref_patterns" "matching on `String` went through without enabling string_deref_patterns"

View File

@ -777,7 +777,7 @@ impl<'tcx> Cx<'tcx> {
if_then_scope: region::Scope { if_then_scope: region::Scope {
id: then.hir_id.local_id, id: then.hir_id.local_id,
data: { data: {
if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope { if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope() {
region::ScopeData::IfThenRescope region::ScopeData::IfThenRescope
} else { } else {
region::ScopeData::IfThen region::ScopeData::IfThen

View File

@ -1126,7 +1126,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
.map(|witness| cx.print_witness_pat(witness)) .map(|witness| cx.print_witness_pat(witness))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(" | "); .join(" | ");
if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns { if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns() {
// Arms with a never pattern don't take a body. // Arms with a never pattern don't take a body.
pattern pattern
} else { } else {

View File

@ -1497,7 +1497,7 @@ fn check_field_tys_sized<'tcx>(
) { ) {
// No need to check if unsized_locals/unsized_fn_params is disabled, // No need to check if unsized_locals/unsized_fn_params is disabled,
// since we will error during typeck. // since we will error during typeck.
if !tcx.features().unsized_locals && !tcx.features().unsized_fn_params { if !tcx.features().unsized_locals() && !tcx.features().unsized_fn_params() {
return; return;
} }

View File

@ -288,7 +288,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()), values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
evaluated: IndexVec::with_capacity(num_values), evaluated: IndexVec::with_capacity(num_values),
next_opaque: Some(1), next_opaque: Some(1),
feature_unsized_locals: tcx.features().unsized_locals, feature_unsized_locals: tcx.features().unsized_locals(),
ssa, ssa,
dominators, dominators,
reused_locals: BitSet::new_empty(local_decls.len()), reused_locals: BitSet::new_empty(local_decls.len()),

View File

@ -12,7 +12,7 @@ use super::layout_test::ensure_wf;
use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField};
pub fn test_abi(tcx: TyCtxt<'_>) { pub fn test_abi(tcx: TyCtxt<'_>) {
if !tcx.features().rustc_attrs { if !tcx.features().rustc_attrs() {
// if the `rustc_attrs` feature is not enabled, don't bother testing ABI // if the `rustc_attrs` feature is not enabled, don't bother testing ABI
return; return;
} }

View File

@ -1187,7 +1187,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
sym::rust_logo => { sym::rust_logo => {
if self.check_attr_crate_level(attr, meta, hir_id) if self.check_attr_crate_level(attr, meta, hir_id)
&& !self.tcx.features().rustdoc_internals && !self.tcx.features().rustdoc_internals()
{ {
feature_err( feature_err(
&self.tcx.sess, &self.tcx.sess,
@ -1774,7 +1774,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
} }
sym::align => { sym::align => {
if let (Target::Fn | Target::Method(MethodKind::Inherent), false) = if let (Target::Fn | Target::Method(MethodKind::Inherent), false) =
(target, self.tcx.features().fn_align) (target, self.tcx.features().fn_align())
{ {
feature_err( feature_err(
&self.tcx.sess, &self.tcx.sess,

View File

@ -105,7 +105,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
// If this crate is not using stability attributes, or this function is not claiming to be a // If this crate is not using stability attributes, or this function is not claiming to be a
// stable `const fn`, that is all that is required. // stable `const fn`, that is all that is required.
if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { if !tcx.features().staged_api() || tcx.has_attr(def_id, sym::rustc_const_unstable) {
return true; return true;
} }

View File

@ -18,7 +18,7 @@ use crate::errors::{
}; };
pub fn test_layout(tcx: TyCtxt<'_>) { pub fn test_layout(tcx: TyCtxt<'_>) {
if !tcx.features().rustc_attrs { if !tcx.features().rustc_attrs() {
// if the `rustc_attrs` feature is not enabled, don't bother testing layout // if the `rustc_attrs` feature is not enabled, don't bother testing layout
return; return;
} }

View File

@ -144,7 +144,7 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures { fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures {
// If `staged_api` is not enabled then we aren't allowed to define lib // If `staged_api` is not enabled then we aren't allowed to define lib
// features; there is no point collecting them. // features; there is no point collecting them.
if !tcx.features().staged_api { if !tcx.features().staged_api() {
return LibFeatures::default(); return LibFeatures::default();
} }

View File

@ -144,7 +144,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
} }
} }
if !self.tcx.features().staged_api { if !self.tcx.features().staged_api() {
// Propagate unstability. This can happen even for non-staged-api crates in case // Propagate unstability. This can happen even for non-staged-api crates in case
// -Zforce-unstable-if-unmarked is set. // -Zforce-unstable-if-unmarked is set.
if let Some(stab) = self.parent_stab { if let Some(stab) = self.parent_stab {
@ -541,7 +541,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
} }
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
if !self.tcx.features().staged_api { if !self.tcx.features().staged_api() {
return; return;
} }
@ -734,7 +734,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// items. // items.
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => { hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
let features = self.tcx.features(); let features = self.tcx.features();
if features.staged_api { if features.staged_api() {
let attrs = self.tcx.hir().attrs(item.hir_id()); let attrs = self.tcx.hir().attrs(item.hir_id());
let stab = attr::find_stability(self.tcx.sess, attrs, item.span); let stab = attr::find_stability(self.tcx.sess, attrs, item.span);
let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span); let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span);
@ -762,7 +762,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
// needs to have an error emitted. // needs to have an error emitted.
if features.const_trait_impl if features.const_trait_impl()
&& self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id()) && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
&& const_stab.is_some_and(|(stab, _)| stab.is_const_stable()) && const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
{ {
@ -926,7 +926,7 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
/// libraries, identify activated features that don't exist and error about them. /// libraries, identify activated features that don't exist and error about them.
pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
let is_staged_api = let is_staged_api =
tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api; tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
if is_staged_api { if is_staged_api {
let effective_visibilities = &tcx.effective_visibilities(()); let effective_visibilities = &tcx.effective_visibilities(());
let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities }; let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };

View File

@ -891,7 +891,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap(); print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
s s
} }
Never if self.tcx.features().never_patterns => "!".to_string(), Never if self.tcx.features().never_patterns() => "!".to_string(),
Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(), Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
Missing { .. } => bug!( Missing { .. } => bug!(
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
@ -915,7 +915,7 @@ fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool {
| Constructor::NonExhaustive | Constructor::NonExhaustive
| Constructor::Hidden | Constructor::Hidden
| Constructor::PrivateUninhabited => true, | Constructor::PrivateUninhabited => true,
Constructor::Never if !tcx.features().never_patterns => true, Constructor::Never if !tcx.features().never_patterns() => true,
_ => false, _ => false,
} }
} }
@ -929,7 +929,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
type PatData = &'p Pat<'tcx>; type PatData = &'p Pat<'tcx>;
fn is_exhaustive_patterns_feature_on(&self) -> bool { fn is_exhaustive_patterns_feature_on(&self) -> bool {
self.tcx.features().exhaustive_patterns self.tcx.features().exhaustive_patterns()
} }
fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize { fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {

View File

@ -115,7 +115,7 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
self.enabled_lang_features().hash_stable(hcx, hasher); self.enabled_lang_features().hash_stable(hcx, hasher);
self.enabled_lib_features().hash_stable(hcx, hasher); self.enabled_lib_features().hash_stable(hcx, hasher);
self.all_lang_features()[..].hash_stable(hcx, hasher); // FIXME: why do we hash something that is a compile-time constant?
for feature in rustc_feature::UNSTABLE_FEATURES.iter() { for feature in rustc_feature::UNSTABLE_FEATURES.iter() {
feature.feature.name.hash_stable(hcx, hasher); feature.feature.name.hash_stable(hcx, hasher);
} }

View File

@ -606,7 +606,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) { Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
Some(binding) => { Some(binding) => {
if matches!(ident.name, sym::f16) if matches!(ident.name, sym::f16)
&& !this.tcx.features().f16 && !this.tcx.features().f16()
&& !ident.span.allows_unstable(sym::f16) && !ident.span.allows_unstable(sym::f16)
&& finalize.is_some() && finalize.is_some()
&& innermost_result.is_none() && innermost_result.is_none()
@ -620,7 +620,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
.emit(); .emit();
} }
if matches!(ident.name, sym::f128) if matches!(ident.name, sym::f128)
&& !this.tcx.features().f128 && !this.tcx.features().f128()
&& !ident.span.allows_unstable(sym::f128) && !ident.span.allows_unstable(sym::f128)
&& finalize.is_some() && finalize.is_some()
&& innermost_result.is_none() && innermost_result.is_none()

View File

@ -2683,7 +2683,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.with_generic_param_rib( self.with_generic_param_rib(
&generics.params, &generics.params,
RibKind::Item( RibKind::Item(
if self.r.tcx.features().generic_const_items { if self.r.tcx.features().generic_const_items() {
HasGenericParams::Yes(generics.span) HasGenericParams::Yes(generics.span)
} else { } else {
HasGenericParams::No HasGenericParams::No
@ -2888,7 +2888,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
RibKind::Normal => { RibKind::Normal => {
// FIXME(non_lifetime_binders): Stop special-casing // FIXME(non_lifetime_binders): Stop special-casing
// const params to error out here. // const params to error out here.
if self.r.tcx.features().non_lifetime_binders if self.r.tcx.features().non_lifetime_binders()
&& matches!(param.kind, GenericParamKind::Type { .. }) && matches!(param.kind, GenericParamKind::Type { .. })
{ {
Res::Def(def_kind, def_id.to_def_id()) Res::Def(def_kind, def_id.to_def_id())
@ -4411,10 +4411,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
let tcx = self.r.tcx(); let tcx = self.r.tcx();
let gate_err_sym_msg = match prim { let gate_err_sym_msg = match prim {
PrimTy::Float(FloatTy::F16) if !tcx.features().f16 => { PrimTy::Float(FloatTy::F16) if !tcx.features().f16() => {
Some((sym::f16, "the type `f16` is unstable")) Some((sym::f16, "the type `f16` is unstable"))
} }
PrimTy::Float(FloatTy::F128) if !tcx.features().f128 => { PrimTy::Float(FloatTy::F128) if !tcx.features().f128() => {
Some((sym::f128, "the type `f128` is unstable")) Some((sym::f128, "the type `f128` is unstable"))
} }
_ => None, _ => None,
@ -4565,7 +4565,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
} }
AnonConstKind::InlineConst => ConstantHasGenerics::Yes, AnonConstKind::InlineConst => ConstantHasGenerics::Yes,
AnonConstKind::ConstArg(_) => { AnonConstKind::ConstArg(_) => {
if self.r.tcx.features().generic_const_exprs || is_trivial_const_arg { if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg {
ConstantHasGenerics::Yes ConstantHasGenerics::Yes
} else { } else {
ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg) ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg)

View File

@ -1198,7 +1198,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
// const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the
// benefits of including them here outweighs the small number of false positives. // benefits of including them here outweighs the small number of false positives.
Some(Res::Def(DefKind::Struct | DefKind::Enum, _)) Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
if self.r.tcx.features().adt_const_params => if self.r.tcx.features().adt_const_params() =>
{ {
Applicability::MaybeIncorrect Applicability::MaybeIncorrect
} }
@ -2773,7 +2773,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
// Avoid suggesting placing lifetime parameters on constant items unless the relevant // Avoid suggesting placing lifetime parameters on constant items unless the relevant
// feature is enabled. Suggest the parent item as a possible location if applicable. // feature is enabled. Suggest the parent item as a possible location if applicable.
if let LifetimeBinderKind::ConstItem = kind if let LifetimeBinderKind::ConstItem = kind
&& !self.r.tcx().features().generic_const_items && !self.r.tcx().features().generic_const_items()
{ {
continue; continue;
} }
@ -2934,7 +2934,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
.emit(); .emit();
} }
NoConstantGenericsReason::NonTrivialConstArg => { NoConstantGenericsReason::NonTrivialConstArg => {
assert!(!self.r.tcx.features().generic_const_exprs); assert!(!self.r.tcx.features().generic_const_exprs());
self.r self.r
.dcx() .dcx()
.create_err(errors::ParamInNonTrivialAnonConst { .create_err(errors::ParamInNonTrivialAnonConst {

View File

@ -661,7 +661,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} }
// We are trying to avoid reporting this error if other related errors were reported. // We are trying to avoid reporting this error if other related errors were reported.
if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes { if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes() {
let is_macro = match res { let is_macro = match res {
Res::Def(..) => true, Res::Def(..) => true,
Res::NonMacroAttr(..) => false, Res::NonMacroAttr(..) => false,
@ -690,7 +690,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&& namespace.ident.name == sym::diagnostic && namespace.ident.name == sym::diagnostic
&& !(attribute.ident.name == sym::on_unimplemented && !(attribute.ident.name == sym::on_unimplemented
|| (attribute.ident.name == sym::do_not_recommend || (attribute.ident.name == sym::do_not_recommend
&& self.tcx.features().do_not_recommend)) && self.tcx.features().do_not_recommend()))
{ {
let distance = let distance =
edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5); edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);

View File

@ -18,7 +18,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
// if the `rustc_attrs` feature is not enabled, then the // if the `rustc_attrs` feature is not enabled, then the
// attributes we are interested in cannot be present anyway, so // attributes we are interested in cannot be present anyway, so
// skip the walk. // skip the walk.
if !tcx.features().rustc_attrs { if !tcx.features().rustc_attrs() {
return; return;
} }

View File

@ -3026,7 +3026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
span: Span, span: Span,
) -> Result<Diag<'a>, ErrorGuaranteed> { ) -> Result<Diag<'a>, ErrorGuaranteed> {
if !self.tcx.features().generic_const_exprs { if !self.tcx.features().generic_const_exprs() {
let guar = self let guar = self
.dcx() .dcx()
.struct_span_err(span, "constant expression depends on a generic parameter") .struct_span_err(span, "constant expression depends on a generic parameter")

View File

@ -3044,7 +3044,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if local { if local {
err.note("all local variables must have a statically known size"); err.note("all local variables must have a statically known size");
} }
if !tcx.features().unsized_locals { if !tcx.features().unsized_locals() {
err.help("unsized locals are gated as an unstable feature"); err.help("unsized locals are gated as an unstable feature");
} }
} }
@ -3125,7 +3125,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.note("all function arguments must have a statically known size"); err.note("all function arguments must have a statically known size");
} }
if tcx.sess.opts.unstable_features.is_nightly_build() if tcx.sess.opts.unstable_features.is_nightly_build()
&& !tcx.features().unsized_fn_params && !tcx.features().unsized_fn_params()
{ {
err.help("unsized fn params are gated as an unstable feature"); err.help("unsized fn params are gated as an unstable feature");
} }
@ -4510,7 +4510,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
) { ) {
// Don't suggest if RTN is active -- we should prefer a where-clause bound instead. // Don't suggest if RTN is active -- we should prefer a where-clause bound instead.
if self.tcx.features().return_type_notation { if self.tcx.features().return_type_notation() {
return; return;
} }

View File

@ -40,7 +40,7 @@ pub fn is_const_evaluatable<'tcx>(
ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
}; };
if tcx.features().generic_const_exprs { if tcx.features().generic_const_exprs() {
let ct = tcx.expand_abstract_consts(unexpanded_ct); let ct = tcx.expand_abstract_consts(unexpanded_ct);
let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() { let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {

View File

@ -254,7 +254,7 @@ fn super_predicates_have_non_lifetime_binders(
trait_def_id: DefId, trait_def_id: DefId,
) -> SmallVec<[Span; 1]> { ) -> SmallVec<[Span; 1]> {
// If non_lifetime_binders is disabled, then exit early // If non_lifetime_binders is disabled, then exit early
if !tcx.features().non_lifetime_binders { if !tcx.features().non_lifetime_binders() {
return SmallVec::new(); return SmallVec::new();
} }
tcx.explicit_super_predicates_of(trait_def_id) tcx.explicit_super_predicates_of(trait_def_id)
@ -327,7 +327,7 @@ pub fn dyn_compatibility_violations_for_assoc_item(
.collect(), .collect(),
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds. // Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
ty::AssocKind::Type => { ty::AssocKind::Type => {
if !tcx.features().generic_associated_types_extended if !tcx.features().generic_associated_types_extended()
&& !tcx.generics_of(item.def_id).is_own_empty() && !tcx.generics_of(item.def_id).is_own_empty()
&& !item.is_impl_trait_in_trait() && !item.is_impl_trait_in_trait()
{ {

View File

@ -598,7 +598,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ty::PredicateKind::ConstEquate(c1, c2) => { ty::PredicateKind::ConstEquate(c1, c2) => {
let tcx = self.selcx.tcx(); let tcx = self.selcx.tcx();
assert!( assert!(
tcx.features().generic_const_exprs, tcx.features().generic_const_exprs(),
"`ConstEquate` without a feature gate: {c1:?} {c2:?}", "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
); );
// FIXME: we probably should only try to unify abstract constants // FIXME: we probably should only try to unify abstract constants

View File

@ -346,7 +346,7 @@ pub fn normalize_param_env_or_error<'tcx>(
let mut predicates: Vec<_> = util::elaborate( let mut predicates: Vec<_> = util::elaborate(
tcx, tcx,
unnormalized_env.caller_bounds().into_iter().map(|predicate| { unnormalized_env.caller_bounds().into_iter().map(|predicate| {
if tcx.features().generic_const_exprs { if tcx.features().generic_const_exprs() {
return predicate; return predicate;
} }

View File

@ -402,7 +402,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
let tcx = self.selcx.tcx(); let tcx = self.selcx.tcx();
if tcx.features().generic_const_exprs if tcx.features().generic_const_exprs()
|| !needs_normalization(&constant, self.param_env.reveal()) || !needs_normalization(&constant, self.param_env.reveal())
{ {
constant constant

View File

@ -189,7 +189,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>(
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e), ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
ProjectAndUnifyResult::Holds(obligations) ProjectAndUnifyResult::Holds(obligations)
if old_universe != new_universe if old_universe != new_universe
&& selcx.tcx().features().generic_associated_types_extended => && selcx.tcx().features().generic_associated_types_extended() =>
{ {
// If the `generic_associated_types_extended` feature is active, then we ignore any // If the `generic_associated_types_extended` feature is active, then we ignore any
// obligations references lifetimes from any universe greater than or equal to the // obligations references lifetimes from any universe greater than or equal to the

View File

@ -876,7 +876,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
if let Some(principal) = data.principal() { if let Some(principal) = data.principal() {
if !self.infcx.tcx.features().dyn_compatible_for_dispatch { if !self.infcx.tcx.features().dyn_compatible_for_dispatch() {
principal.with_self_ty(self.tcx(), self_ty) principal.with_self_ty(self.tcx(), self_ty)
} else if self.tcx().is_dyn_compatible(principal.def_id()) { } else if self.tcx().is_dyn_compatible(principal.def_id()) {
principal.with_self_ty(self.tcx(), self_ty) principal.with_self_ty(self.tcx(), self_ty)
@ -936,7 +936,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
let tcx = self.tcx(); let tcx = self.tcx();
if tcx.features().trait_upcasting { if tcx.features().trait_upcasting() {
return None; return None;
} }

View File

@ -402,7 +402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut assume = predicate.trait_ref.args.const_at(2); let mut assume = predicate.trait_ref.args.const_at(2);
// FIXME(min_generic_const_exprs): We should shallowly normalize this. // FIXME(min_generic_const_exprs): We should shallowly normalize this.
if self.tcx().features().generic_const_exprs { if self.tcx().features().generic_const_exprs() {
assume = assume.normalize_internal(self.tcx(), obligation.param_env); assume = assume.normalize_internal(self.tcx(), obligation.param_env);
} }
let Some(assume) = let Some(assume) =
@ -626,7 +626,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
for assoc_type in assoc_types { for assoc_type in assoc_types {
let defs: &ty::Generics = tcx.generics_of(assoc_type); let defs: &ty::Generics = tcx.generics_of(assoc_type);
if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended { if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended() {
tcx.dcx().span_delayed_bug( tcx.dcx().span_delayed_bug(
obligation.cause.span, obligation.cause.span,
"GATs in trait object shouldn't have been considered", "GATs in trait object shouldn't have been considered",

View File

@ -865,7 +865,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::PredicateKind::ConstEquate(c1, c2) => { ty::PredicateKind::ConstEquate(c1, c2) => {
let tcx = self.tcx(); let tcx = self.tcx();
assert!( assert!(
tcx.features().generic_const_exprs, tcx.features().generic_const_exprs(),
"`ConstEquate` without a feature gate: {c1:?} {c2:?}", "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
); );
@ -2195,7 +2195,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
match self.tcx().coroutine_movability(coroutine_def_id) { match self.tcx().coroutine_movability(coroutine_def_id) {
hir::Movability::Static => None, hir::Movability::Static => None,
hir::Movability::Movable => { hir::Movability::Movable => {
if self.tcx().features().coroutine_clone { if self.tcx().features().coroutine_clone() {
let resolved_upvars = let resolved_upvars =
self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
let resolved_witness = let resolved_witness =

View File

@ -136,7 +136,7 @@ pub fn translate_args_with_cause<'tcx>(
} }
pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool { pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool {
tcx.features().specialization || tcx.features().min_specialization tcx.features().specialization() || tcx.features().min_specialization()
} }
/// Is `impl1` a specialization of `impl2`? /// Is `impl1` a specialization of `impl2`?

View File

@ -82,7 +82,7 @@ impl<'tcx> At<'_, 'tcx> {
} }
Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
} else if self.infcx.tcx.features().generic_const_exprs { } else if self.infcx.tcx.features().generic_const_exprs() {
Ok(ct.normalize_internal(self.infcx.tcx, self.param_env)) Ok(ct.normalize_internal(self.infcx.tcx, self.param_env))
} else { } else {
Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))

View File

@ -836,7 +836,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
// obligations that don't refer to Self and // obligations that don't refer to Self and
// checking those // checking those
let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch; let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch();
if !defer_to_coercion { if !defer_to_coercion {
if let Some(principal) = data.principal_def_id() { if let Some(principal) = data.principal_def_id() {

View File

@ -181,7 +181,7 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> { fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
// don't synthesize the associated type even if the user has written `const_trait` // don't synthesize the associated type even if the user has written `const_trait`
// if the effects feature is disabled. // if the effects feature is disabled.
if !tcx.features().effects { if !tcx.features().effects() {
return None; return None;
} }
let (feed, parent_did) = match tcx.def_kind(def_id) { let (feed, parent_did) = match tcx.def_kind(def_id) {

Some files were not shown because too many files have changed in this diff Show More