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::LoongArch64
);
if !is_stable && !self.tcx.features().asm_experimental_arch {
if !is_stable && !self.tcx.features().asm_experimental_arch() {
feature_err(
&self.tcx.sess,
sym::asm_experimental_arch,
@ -65,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
{
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(
&self.tcx.sess,
sym::asm_unwind,
@ -237,7 +237,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
InlineAsmOperand::Label { block } => {
if !self.tcx.features().asm_goto {
if !self.tcx.features().asm_goto() {
feature_err(
sess,
sym::asm_goto,

View File

@ -575,7 +575,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} else {
// Either `body.is_none()` or `is_never_pattern` here.
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.
let suggestion = span.shrink_to_hi();
self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
@ -717,7 +717,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
outer_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)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
{
@ -1572,7 +1572,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
}
Some(hir::CoroutineKind::Coroutine(_)) => {
if !self.tcx.features().coroutines {
if !self.tcx.features().coroutines() {
rustc_session::parse::feature_err(
&self.tcx.sess,
sym::coroutines,
@ -1584,7 +1584,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
false
}
None => {
if !self.tcx.features().coroutines {
if !self.tcx.features().coroutines() {
rustc_session::parse::feature_err(
&self.tcx.sess,
sym::coroutines,

View File

@ -1512,7 +1512,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
continue;
}
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
.sess
.create_feature_err(
@ -1530,7 +1530,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
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
// 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 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_bounds: Vec::new(),
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()
} else {
[sym::gen_future].into()
@ -1035,7 +1035,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: data.inputs_span,
})
};
if !self.tcx.features().return_type_notation
if !self.tcx.features().return_type_notation()
&& self.tcx.sess.is_nightly_build()
{
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::Type(ty) => {
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 {
hir_id: self.lower_node_id(ty.id),
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
// on a per-opaque basis to account for nested opaques.
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::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
hir::OpaqueTyOrigin::AsyncFn { .. } => {
@ -1519,7 +1519,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Feature gate for RPITIT + use<..>
match origin {
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 {
ast::GenericBound::Use(_, span) => Some(span),
_ => None,
@ -2270,7 +2270,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
match c.value.kind {
ExprKind::Underscore => {
if self.tcx.features().generic_arg_infer {
if self.tcx.features().generic_arg_infer() {
hir::ArrayLen::Infer(hir::InferArg {
hir_id: self.lower_node_id(c.id),
span: self.lower_span(c.value.span),

View File

@ -268,7 +268,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: data.inputs_span,
})
};
if !self.tcx.features().return_type_notation
if !self.tcx.features().return_type_notation()
&& self.tcx.sess.is_nightly_build()
{
add_feature_diagnostics(
@ -496,7 +496,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
// ```
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)
} else {
self.lower_ty(

View File

@ -295,7 +295,8 @@ impl<'a> AstValidator<'a> {
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 {
constness: Const::No,
polarity: ImplPolarity::Positive,
@ -308,13 +309,12 @@ impl<'a> AstValidator<'a> {
None
};
let make_trait_const_sugg = if self.features.const_trait_impl
&& let TraitOrTraitImpl::Trait { span, constness: None } = parent
{
Some(span.shrink_to_lo())
} else {
None
};
let make_trait_const_sugg =
if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent {
Some(span.shrink_to_lo())
} else {
None
};
let parent_constness = parent.constness();
self.dcx().emit_err(errors::TraitFnConst {
@ -1145,7 +1145,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
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) {
self.dcx().emit_err(err);
}
@ -1286,7 +1286,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
GenericBound::Trait(trait_ref) => {
match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
if !self.features.more_maybe_bounds =>
if !self.features.more_maybe_bounds() =>
{
self.sess
.create_feature_err(
@ -1299,7 +1299,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.emit();
}
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
if !self.features.more_maybe_bounds =>
if !self.features.more_maybe_bounds() =>
{
self.sess
.create_feature_err(

View File

@ -15,13 +15,13 @@ use crate::errors;
/// The common case.
macro_rules! gate {
($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
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
}
}};
($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
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
@ -43,7 +43,7 @@ macro_rules! gate_alt {
/// The case involving a multispan.
macro_rules! gate_multi {
($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{
if !$visitor.features.$feature {
if !$visitor.features.$feature() {
let spans: Vec<_> =
$spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
if !spans.is_empty() {
@ -56,7 +56,7 @@ macro_rules! gate_multi {
/// The legacy case.
macro_rules! gate_legacy {
($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);
}
}};
@ -150,7 +150,7 @@ impl<'a> PostExpansionVisitor<'a> {
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
// 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
.iter()
.filter_map(|param| match param.kind {
@ -210,7 +210,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
// Emit errors for non-staged-api crates.
if !self.features.staged_api {
if !self.features.staged_api() {
if attr.has_name(sym::unstable)
|| attr.has_name(sym::stable)
|| 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.
gate_alt!(
&self,
self.features.specialization || (is_fn && self.features.min_specialization),
self.features.specialization() || (is_fn && self.features.min_specialization()),
sym::specialization,
i.span,
"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!(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) {
for &span in spans {
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() {
sess.dcx().emit_err(errors::NegativeBoundUnsupported { span });
}

View File

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

View File

@ -1035,7 +1035,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn unsized_feature_enabled(&self) -> bool {
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

View File

@ -69,7 +69,7 @@ pub(crate) fn expand_assert<'cx>(
// If `generic_assert` is enabled, generates rich captured outputs
//
// 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())
}
// 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();
match inner.as_deref() {
Some([item]) if item.has_name(sym::linker) => {
if !tcx.features().used_with_arg {
if !tcx.features().used_with_arg() {
feature_err(
&tcx.sess,
sym::used_with_arg,
@ -149,7 +149,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
}
Some([item]) if item.has_name(sym::compiler) => {
if !tcx.features().used_with_arg {
if !tcx.features().used_with_arg() {
feature_err(
&tcx.sess,
sym::used_with_arg,
@ -213,7 +213,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
.emit();
}
if is_closure
&& !tcx.features().closure_track_caller
&& !tcx.features().closure_track_caller()
&& !attr.span.allows_unstable(sym::closure_track_caller)
{
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
// `#[target_feature]` on `main` and `start`.
} else if !tcx.features().target_feature_11 {
} else if !tcx.features().target_feature_11() {
feature_err(
&tcx.sess,
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
// 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.
if tcx.features().target_feature_11
if tcx.features().target_feature_11()
&& tcx.is_closure_like(did.to_def_id())
&& 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.
let allowed = match feature_gate.as_ref().copied() {
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
Some(sym::ermsb_target_feature) => rust_features.ermsb_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::csky_target_feature) => rust_features.csky_target_feature,
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86,
Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
Some(sym::xop_target_feature) => rust_features.xop_target_feature,
Some(sym::s390x_target_feature) => rust_features.s390x_target_feature,
Some(sym::arm_target_feature) => rust_features.arm_target_feature(),
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature(),
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature(),
Some(sym::mips_target_feature) => rust_features.mips_target_feature(),
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature(),
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature(),
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature(),
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature(),
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature(),
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature(),
Some(sym::ermsb_target_feature) => rust_features.ermsb_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::csky_target_feature) => rust_features.csky_target_feature(),
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature(),
Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature(),
Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature(),
Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86(),
Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics(),
Some(sym::xop_target_feature) => rust_features.xop_target_feature(),
Some(sym::s390x_target_feature) => rust_features.s390x_target_feature(),
Some(name) => bug!("unknown target feature gate {}", name),
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
// checks.
// FIXME(effects) we might consider moving const stability checks to typeck as well.
if tcx.features().effects {
if tcx.features().effects() {
is_trait = true;
if let Ok(Some(instance)) =
@ -631,7 +631,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
args: fn_args,
span: *fn_span,
call_source,
feature: Some(if tcx.features().const_trait_impl {
feature: Some(if tcx.features().const_trait_impl() {
sym::effects
} else {
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 {
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())
}

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.

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 let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
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;
}
@ -103,7 +103,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
}
// 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
// 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
@ -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);
}
features.set_enabled_lang_feature(name, mi.span(), None, Some(f));
features.set_enabled_lang_feature(name, mi.span(), None);
continue;
}
@ -395,7 +395,7 @@ impl<'a> StripUnconfigured<'a> {
/// If attributes are not allowed on expressions, emit an error for `attr`
#[instrument(level = "trace", skip(self))]
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)
{
let mut err = feature_err(

View File

@ -867,7 +867,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
| Annotatable::FieldDef(..)
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
};
if self.cx.ecfg.features.proc_macro_hygiene {
if self.cx.ecfg.features.proc_macro_hygiene() {
return;
}
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 });
}
}

View File

@ -121,14 +121,14 @@ pub(super) fn parse(
/// 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) {
if !features.macro_metavar_expr {
if !features.macro_metavar_expr() {
let msg = "meta-variable expressions are unstable";
feature_err(sess, sym::macro_metavar_expr, span, msg).emit();
}
}
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";
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 {
($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 {
match sym {
sym::on_unimplemented => true,
sym::do_not_recommend => features.do_not_recommend,
sym::do_not_recommend => features.do_not_recommend(),
_ => false,
}
}

View File

@ -8,7 +8,6 @@ use super::{Feature, to_nonzero};
pub struct UnstableFeature {
pub feature: Feature,
set_enabled: fn(&mut Features),
}
#[derive(PartialEq)]
@ -30,6 +29,53 @@ macro_rules! status_to_enum {
};
}
/// 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)]
pub struct Features {
/// `#![feature]` attrs for language features, for error reporting.
enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
/// `#![feature]` attrs for non-language (library) features.
enabled_lib_features: Vec<(Symbol, Span)>,
/// `enabled_lang_features` + `enabled_lib_features`.
enabled_features: FxHashSet<Symbol>,
}
impl Features {
pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option<Symbol>) {
self.enabled_lang_features.push((name, span, since));
self.enabled_features.insert(name);
}
pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) {
self.enabled_lib_features.push((name, span));
self.enabled_features.insert(name);
}
pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> {
&self.enabled_lang_features
}
pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> {
&self.enabled_lib_features
}
pub fn enabled_features(&self) -> &FxHashSet<Symbol> {
&self.enabled_features
}
/// Is the given feature enabled (via `#[feature(...)]`)?
pub fn enabled(&self, feature: Symbol) -> bool {
self.enabled_features.contains(&feature)
}
}
macro_rules! declare_features {
($(
$(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr),
@ -43,97 +89,15 @@ macro_rules! declare_features {
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.
#[derive(Clone, Default, Debug)]
pub struct Features {
/// `#![feature]` attrs for language features, for error reporting.
enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
/// `#![feature]` attrs for non-language (library) features.
enabled_lib_features: Vec<(Symbol, Span)>,
/// `enabled_lang_features` + `enabled_lib_features`.
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 {
pub fn set_enabled_lang_feature(
&mut self,
name: Symbol,
span: Span,
since: Option<Symbol>,
feature: Option<&UnstableFeature>,
) {
self.enabled_lang_features.push((name, span, since));
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 $feature(&self) -> bool {
self.enabled_features.contains(&sym::$feature)
}
}
pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) {
self.enabled_lib_features.push((name, span));
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>)> {
&self.enabled_lang_features
}
pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> {
&self.enabled_lib_features
}
pub fn enabled_features(&self) -> &FxHashSet<Symbol> {
&self.enabled_features
}
/// Is the given feature enabled (via `#[feature(...)]`)?
pub fn enabled(&self, feature: Symbol) -> bool {
let e = 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
}
)*
/// 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

View File

@ -72,7 +72,7 @@ impl<'tcx> Bounds<'tcx> {
// 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
// type bounds.
if !tcx.features().effects {
if !tcx.features().effects() {
return;
}
match predicate_filter {

View File

@ -1166,7 +1166,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
return;
}
if adt.is_union() && !tcx.features().transparent_unions {
if adt.is_union() && !tcx.features().transparent_unions() {
feature_err(
&tcx.sess,
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);
if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
if !tcx.features().repr128 {
if !tcx.features().repr128() {
feature_err(
&tcx.sess,
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 visitor.tcx.features().shorter_tail_lifetimes
if visitor.tcx.features().shorter_tail_lifetimes()
&& blk.span.edition().at_least_rust_2024()
{
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)) => {
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
} else {
ScopeData::IfThen
@ -481,7 +482,8 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
hir::ExprKind::If(cond, then, None) => {
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
} else {
ScopeData::IfThen

View File

@ -110,7 +110,7 @@ where
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()
}
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();
if tcx.features().unsized_const_params {
if tcx.features().unsized_const_params() {
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
wfcx.register_bound(
ObligationCause::new(
@ -935,7 +935,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
);
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| {
wfcx.register_bound(
ObligationCause::new(
@ -1698,9 +1698,9 @@ fn check_method_receiver<'tcx>(
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)
} else if tcx.features().arbitrary_self_types {
} else if tcx.features().arbitrary_self_types() {
Some(ArbitrarySelfTypesLevel::Basic)
} else {
None

View File

@ -77,7 +77,7 @@ impl<'tcx> InherentCollect<'tcx> {
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);
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
@ -115,7 +115,7 @@ impl<'tcx> InherentCollect<'tcx> {
) -> Result<(), ErrorGuaranteed> {
let items = self.tcx.associated_item_def_ids(impl_def_id);
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 {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let span = self.tcx.def_span(impl_def_id);

View File

@ -53,7 +53,7 @@ fn enforce_trait_manually_implementable(
) -> Result<(), ErrorGuaranteed> {
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(
&tcx.sess,
sym::freeze_impls,
@ -86,8 +86,8 @@ fn enforce_trait_manually_implementable(
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind
{
if !tcx.features().specialization
&& !tcx.features().min_specialization
if !tcx.features().specialization()
&& !tcx.features().min_specialization()
&& !impl_header_span.allows_unstable(sym::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);
if paren_sugar && !tcx.features().unboxed_closures {
if paren_sugar && !tcx.features().unboxed_closures() {
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
// 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<'_>| {
if ty.is_simd() {
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
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.features().generic_const_exprs {
} else if tcx.features().generic_const_exprs() {
let parent_node = tcx.parent_hir_node(hir_id);
debug!(?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));
}
@ -524,7 +524,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
} else {
if matches!(def_kind, DefKind::AnonConst)
&& tcx.features().generic_const_exprs
&& tcx.features().generic_const_exprs()
&& let Some(defaulted_param_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)
&& param.is_elided_lifetime()
&& !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(
&self.tcx.sess,
@ -2239,7 +2239,7 @@ fn deny_non_region_late_bound(
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;
*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) {
if !tcx.features().inherent_associated_types {
if !tcx.features().inherent_associated_types() {
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
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 {
use hir::intravisit::Visitor;
if tcx.features().lazy_type_alias {
if tcx.features().lazy_type_alias() {
return true;
}
struct HasTait;

View File

@ -88,7 +88,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
if seen_repeat {
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();
};
}

View File

@ -63,7 +63,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_segment: &'_ hir::PathSegment<'_>,
is_impl: bool,
) {
if self.tcx().features().unboxed_closures {
if self.tcx().features().unboxed_closures() {
return;
}
@ -343,7 +343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&& let Some(hir_ty) = constraint.ty()
&& let ty = self.lower_ty(hir_ty)
&& (ty.is_enum() || ty.references_error())
&& tcx.features().associated_const_equality
&& tcx.features().associated_const_equality()
{
Some(errors::AssocKindMismatchWrapInBracesSugg {
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
// errors (#108491) which mask the feature-gate error, needlessly confusing users
// who use IATs by accident (#113265).
if !tcx.features().inherent_associated_types {
if !tcx.features().inherent_associated_types() {
return Ok(None);
}

View File

@ -57,7 +57,7 @@ pub(crate) fn check_impl_wf(
tcx: TyCtxt<'_>,
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let min_specialization = tcx.features().min_specialization;
let min_specialization = tcx.features().min_specialization();
let mut res = Ok(());
debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
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;
}
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()) {
// User enabled additional ABI support for varargs and function ABI matches those ones.
(true, true) => return,
@ -155,7 +155,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
// FIXME(effects): remove once effects is implemented in old trait solver
// 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);
}
@ -172,7 +172,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
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("variance_dumping", || variance::dump::variances(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(());
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);
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

View File

@ -721,7 +721,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
use rustc_middle::ty::cast::IntTy::*;
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`");
} else {
// 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) => {
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);
}
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) =>
{
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
&& !self.tcx().features().trait_upcasting
&& !self.tcx().features().trait_upcasting()
{
// Renders better when we erase regions, since they're not really the point here.
let (sub, sup) = self.tcx.erase_regions((sub, sup));
@ -712,7 +712,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
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(
&self.tcx.sess,
sym::unsized_tuple_coercion,
@ -732,7 +732,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
b_region: ty::Region<'tcx>,
) -> CoerceResult<'tcx> {
if !self.tcx.features().dyn_star {
if !self.tcx.features().dyn_star() {
return Err(TypeError::Mismatch);
}
@ -1695,7 +1695,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
blk_id,
expression,
);
if !fcx.tcx.features().unsized_locals {
if !fcx.tcx.features().unsized_locals() {
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,
expression,
);
if !fcx.tcx.features().unsized_locals {
if !fcx.tcx.features().unsized_locals() {
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).
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,
// but don't want to expose the removal to stable Rust.
// 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 {
// FIXME: We are currently creating two branches here in order to maintain
// 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() {
// Make some fresh generic parameters for our ADT type.
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) =
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(
&self.tcx.sess,
sym::offset_of_enum,
@ -3642,7 +3642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
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(
field_ty,
expr.span,
@ -3675,7 +3675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& field.name == sym::integer(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(
field_ty,
expr.span,

View File

@ -1486,7 +1486,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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)
} else {
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
if tcx.features().never_type_fallback {
if tcx.features().never_type_fallback() {
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);
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(
var_ty,
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(
var_ty,
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 = 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 {
let expected_type = infer_type_if_missing(&fcx, node);
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
// situations where this can occur by adding additional restrictions
// 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()
.report_mismatched_types(&cause, method_self_ty, self_ty, terr)
.emit();

View File

@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mode,
}));
} 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()
{
// 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 guar = match *ty.kind() {
ty::Infer(ty::TyVar(_)) => {
let raw_ptr_call =
bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types;
let raw_ptr_call = bad_ty.reached_raw_pointer
&& !self.tcx.features().arbitrary_self_types();
let mut err = self.err_ctxt().emit_inference_failure_err(
self.body_id,
span,
@ -1146,7 +1146,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
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) =>
{
// 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>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
if !self.tcx.features().pin_ergonomics {
if !self.tcx.features().pin_ergonomics() {
return None;
}

View File

@ -442,7 +442,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
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());
if def_br == ByRef::Yes(Mutability::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 tcx = self.tcx;
@ -675,10 +676,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let bm = match user_bind_annot {
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
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_structural)
&& (self.tcx.features().ref_pat_eat_one_layer_2024()
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural())
{
if !self.tcx.features().mut_ref {
if !self.tcx.features().mut_ref() {
feature_err(
&self.tcx.sess,
sym::mut_ref,
@ -2152,8 +2153,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
let tcx = self.tcx;
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_structural = features.ref_pat_eat_one_layer_2024_structural;
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 no_ref_mut_behind_and =
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);
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
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);
// Normalize consts in writeback, because GCE doesn't normalize eagerly.
if tcx.features().generic_const_exprs {
if tcx.features().generic_const_exprs() {
value =
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
// attributes we are interested in cannot be present anyway, so
// skip the walk.
if !tcx.features().rustc_attrs {
if !tcx.features().rustc_attrs() {
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
if !tcx.features().rustc_attrs {
if !tcx.features().rustc_attrs() {
return;
}

View File

@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
&& 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"
if cx.tcx.features().return_type_notation {
if cx.tcx.features().return_type_notation() {
return;
}

View File

@ -1235,7 +1235,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
def_id: LocalDefId,
) {
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
&& 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`.
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)
&& cx.tcx.features().generic_const_exprs
&& cx.tcx.features().generic_const_exprs()
{
return;
}
@ -1538,7 +1538,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
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);
for &(predicate, span) in predicates.predicates {
let predicate_kind_name = match predicate.kind().skip_binder() {

View File

@ -243,7 +243,7 @@ impl_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
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;
}
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
{
let opaque_span = self.tcx.def_span(opaque_def_id);
let new_capture_rules =
opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024;
let new_capture_rules = opaque_span.at_least_rust_2024()
|| self.tcx.features().lifetime_capture_rules_2024();
if !new_capture_rules
&& !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
{

View File

@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder {
_: Span,
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);
}
}

View File

@ -170,7 +170,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
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`
// 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
}
"link-arg" => {
if !features.link_arg_attribute {
if !features.link_arg_attribute() {
feature_err(
sess,
sym::link_arg_attribute,
@ -314,7 +314,7 @@ impl<'tcx> Collector<'tcx> {
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue;
};
if !features.link_cfg {
if !features.link_cfg() {
feature_err(
sess,
sym::link_cfg,
@ -384,7 +384,7 @@ impl<'tcx> Collector<'tcx> {
};
macro report_unstable_modifier($feature: ident) {
if !features.$feature {
if !features.$feature() {
// FIXME: make this translatable
#[expect(rustc::untranslatable_diagnostic)]
feature_err(

View File

@ -1765,7 +1765,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
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 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) {
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) {
// 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.
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) {
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) {
// 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.
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) {
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
// used generic parameters is a bug of evaluation, so checking for it
// 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());
assert!(
matches!(

View File

@ -61,7 +61,7 @@ pub enum OverlapMode {
impl 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);
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 {
fn generic_const_exprs(self) -> bool {
self.generic_const_exprs
self.generic_const_exprs()
}
fn coroutine_clone(self) -> bool {
self.coroutine_clone
self.coroutine_clone()
}
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);
if len_eval == Some(0) {
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, .. }) =
self.tcx().opt_rpitit_info(def_id)
&& let ty::Alias(_, alias_ty) =

View File

@ -750,7 +750,7 @@ impl<'tcx> Ty<'tcx> {
#[inline]
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

View File

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

View File

@ -163,7 +163,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let tcx = this.tcx;
if tcx.features().unsized_fn_params {
if tcx.features().unsized_fn_params() {
let ty = expr.ty;
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()
&& tcx.is_lang_item(def.did(), LangItem::String)
{
if !tcx.features().string_deref_patterns {
if !tcx.features().string_deref_patterns() {
span_bug!(
test.span,
"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 {
id: then.hir_id.local_id,
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
} else {
region::ScopeData::IfThen

View File

@ -1126,7 +1126,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
.map(|witness| cx.print_witness_pat(witness))
.collect::<Vec<String>>()
.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.
pattern
} 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,
// 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;
}

View File

@ -288,7 +288,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
evaluated: IndexVec::with_capacity(num_values),
next_opaque: Some(1),
feature_unsized_locals: tcx.features().unsized_locals,
feature_unsized_locals: tcx.features().unsized_locals(),
ssa,
dominators,
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};
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
return;
}

View File

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

View File

@ -18,7 +18,7 @@ use crate::errors::{
};
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
return;
}

View File

@ -144,7 +144,7 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures {
// If `staged_api` is not enabled then we aren't allowed to define lib
// features; there is no point collecting them.
if !tcx.features().staged_api {
if !tcx.features().staged_api() {
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
// -Zforce-unstable-if-unmarked is set.
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) {
if !self.tcx.features().staged_api {
if !self.tcx.features().staged_api() {
return;
}
@ -734,7 +734,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// items.
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
let features = self.tcx.features();
if features.staged_api {
if features.staged_api() {
let attrs = self.tcx.hir().attrs(item.hir_id());
let stab = attr::find_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
// 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())
&& 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.
pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
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 {
let effective_visibilities = &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();
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(),
Missing { .. } => 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::Hidden
| Constructor::PrivateUninhabited => true,
Constructor::Never if !tcx.features().never_patterns => true,
Constructor::Never if !tcx.features().never_patterns() => true,
_ => false,
}
}
@ -929,7 +929,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
type PatData = &'p Pat<'tcx>;
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 {

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_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() {
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) {
Some(binding) => {
if matches!(ident.name, sym::f16)
&& !this.tcx.features().f16
&& !this.tcx.features().f16()
&& !ident.span.allows_unstable(sym::f16)
&& finalize.is_some()
&& innermost_result.is_none()
@ -620,7 +620,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
.emit();
}
if matches!(ident.name, sym::f128)
&& !this.tcx.features().f128
&& !this.tcx.features().f128()
&& !ident.span.allows_unstable(sym::f128)
&& finalize.is_some()
&& 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(
&generics.params,
RibKind::Item(
if self.r.tcx.features().generic_const_items {
if self.r.tcx.features().generic_const_items() {
HasGenericParams::Yes(generics.span)
} else {
HasGenericParams::No
@ -2888,7 +2888,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
RibKind::Normal => {
// FIXME(non_lifetime_binders): Stop special-casing
// 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 { .. })
{
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 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"))
}
PrimTy::Float(FloatTy::F128) if !tcx.features().f128 => {
PrimTy::Float(FloatTy::F128) if !tcx.features().f128() => {
Some((sym::f128, "the type `f128` is unstable"))
}
_ => None,
@ -4565,7 +4565,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
AnonConstKind::InlineConst => ConstantHasGenerics::Yes,
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
} else {
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
// benefits of including them here outweighs the small number of false positives.
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
}
@ -2773,7 +2773,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
// Avoid suggesting placing lifetime parameters on constant items unless the relevant
// feature is enabled. Suggest the parent item as a possible location if applicable.
if let LifetimeBinderKind::ConstItem = kind
&& !self.r.tcx().features().generic_const_items
&& !self.r.tcx().features().generic_const_items()
{
continue;
}
@ -2934,7 +2934,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
.emit();
}
NoConstantGenericsReason::NonTrivialConstArg => {
assert!(!self.r.tcx.features().generic_const_exprs);
assert!(!self.r.tcx.features().generic_const_exprs());
self.r
.dcx()
.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.
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 {
Res::Def(..) => true,
Res::NonMacroAttr(..) => false,
@ -690,7 +690,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&& namespace.ident.name == sym::diagnostic
&& !(attribute.ident.name == sym::on_unimplemented
|| (attribute.ident.name == sym::do_not_recommend
&& self.tcx.features().do_not_recommend))
&& self.tcx.features().do_not_recommend()))
{
let distance =
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
// attributes we are interested in cannot be present anyway, so
// skip the walk.
if !tcx.features().rustc_attrs {
if !tcx.features().rustc_attrs() {
return;
}

View File

@ -3026,7 +3026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
obligation: &PredicateObligation<'tcx>,
span: Span,
) -> Result<Diag<'a>, ErrorGuaranteed> {
if !self.tcx.features().generic_const_exprs {
if !self.tcx.features().generic_const_exprs() {
let guar = self
.dcx()
.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 {
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");
}
}
@ -3125,7 +3125,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.note("all function arguments must have a statically known size");
}
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");
}
@ -4510,7 +4510,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref: ty::PolyTraitRef<'tcx>,
) {
// 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;
}

View File

@ -40,7 +40,7 @@ pub fn is_const_evaluatable<'tcx>(
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 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,
) -> SmallVec<[Span; 1]> {
// If non_lifetime_binders is disabled, then exit early
if !tcx.features().non_lifetime_binders {
if !tcx.features().non_lifetime_binders() {
return SmallVec::new();
}
tcx.explicit_super_predicates_of(trait_def_id)
@ -327,7 +327,7 @@ pub fn dyn_compatibility_violations_for_assoc_item(
.collect(),
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
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()
&& !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) => {
let tcx = self.selcx.tcx();
assert!(
tcx.features().generic_const_exprs,
tcx.features().generic_const_exprs(),
"`ConstEquate` without a feature gate: {c1:?} {c2:?}",
);
// 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(
tcx,
unnormalized_env.caller_bounds().into_iter().map(|predicate| {
if tcx.features().generic_const_exprs {
if tcx.features().generic_const_exprs() {
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")]
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'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())
{
constant

View File

@ -189,7 +189,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>(
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
ProjectAndUnifyResult::Holds(obligations)
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
// 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 !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)
} else if self.tcx().is_dyn_compatible(principal.def_id()) {
principal.with_self_ty(self.tcx(), self_ty)
@ -936,7 +936,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
let tcx = self.tcx();
if tcx.features().trait_upcasting {
if tcx.features().trait_upcasting() {
return None;
}

View File

@ -402,7 +402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut assume = predicate.trait_ref.args.const_at(2);
// 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);
}
let Some(assume) =
@ -626,7 +626,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
for assoc_type in assoc_types {
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(
obligation.cause.span,
"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) => {
let tcx = self.tcx();
assert!(
tcx.features().generic_const_exprs,
tcx.features().generic_const_exprs(),
"`ConstEquate` without a feature gate: {c1:?} {c2:?}",
);
@ -2195,7 +2195,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
match self.tcx().coroutine_movability(coroutine_def_id) {
hir::Movability::Static => None,
hir::Movability::Movable => {
if self.tcx().features().coroutine_clone {
if self.tcx().features().coroutine_clone() {
let resolved_upvars =
self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
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 {
tcx.features().specialization || tcx.features().min_specialization
tcx.features().specialization() || tcx.features().min_specialization()
}
/// 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))
} 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))
} else {
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
// 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 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> {
// don't synthesize the associated type even if the user has written `const_trait`
// if the effects feature is disabled.
if !tcx.features().effects {
if !tcx.features().effects() {
return None;
}
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