mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 05:51:58 +00:00
Auto merge of #116437 - nnethercote:rustc_features, r=Nilstrieb
Clean up `rustc_features` Plenty more to be done, but this is a decent start. r? `@Nilstrieb`
This commit is contained in:
commit
cf21a0823b
@ -13,17 +13,16 @@ use rustc_ast::NodeId;
|
||||
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_feature::{Feature, Features, State as FeatureState};
|
||||
use rustc_feature::{
|
||||
ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
|
||||
};
|
||||
use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES};
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::{Edition, ALL_EDITIONS};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
/// A folder that strips out items that do not belong in the current configuration.
|
||||
pub struct StripUnconfigured<'a> {
|
||||
@ -37,13 +36,6 @@ pub struct StripUnconfigured<'a> {
|
||||
}
|
||||
|
||||
pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
||||
fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) {
|
||||
sess.emit_err(FeatureRemoved {
|
||||
span,
|
||||
reason: reason.map(|reason| FeatureRemovedReason { reason }),
|
||||
});
|
||||
}
|
||||
|
||||
fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> {
|
||||
ACTIVE_FEATURES.iter().filter(move |feature| {
|
||||
if let Some(feature_edition) = feature.edition {
|
||||
@ -54,67 +46,49 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
||||
})
|
||||
}
|
||||
|
||||
fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
|
||||
if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() {
|
||||
list
|
||||
} else {
|
||||
ThinVec::new()
|
||||
}
|
||||
}
|
||||
|
||||
let mut features = Features::default();
|
||||
let mut edition_enabled_features = FxHashMap::default();
|
||||
|
||||
// The edition from `--edition`.
|
||||
let crate_edition = sess.edition();
|
||||
|
||||
for &edition in ALL_EDITIONS {
|
||||
if edition <= crate_edition {
|
||||
// The `crate_edition` implies its respective umbrella feature-gate
|
||||
// (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
|
||||
edition_enabled_features.insert(edition.feature_name(), edition);
|
||||
}
|
||||
}
|
||||
|
||||
for feature in active_features_up_to(crate_edition) {
|
||||
feature.set(&mut features, DUMMY_SP);
|
||||
edition_enabled_features.insert(feature.name, crate_edition);
|
||||
}
|
||||
|
||||
// Process the edition umbrella feature-gates first, to ensure
|
||||
// `edition_enabled_features` is completed before it's queried.
|
||||
// The maximum of (a) the edition from `--edition` and (b) any edition
|
||||
// umbrella feature-gates declared in the code.
|
||||
// - E.g. if `crate_edition` is 2015 but `rust_2018_preview` is present,
|
||||
// `feature_edition` is 2018
|
||||
let mut features_edition = crate_edition;
|
||||
for attr in krate_attrs {
|
||||
if !attr.has_name(sym::feature) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(list) = attr.meta_item_list() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for mi in list {
|
||||
if !mi.is_word() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = mi.name_or_empty();
|
||||
|
||||
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
|
||||
if let Some(edition) = edition {
|
||||
if edition <= crate_edition {
|
||||
continue;
|
||||
}
|
||||
|
||||
for feature in active_features_up_to(edition) {
|
||||
// FIXME(Manishearth) there is currently no way to set
|
||||
// lib features by edition
|
||||
feature.set(&mut features, DUMMY_SP);
|
||||
edition_enabled_features.insert(feature.name, edition);
|
||||
for mi in feature_list(attr) {
|
||||
if mi.is_word() {
|
||||
let name = mi.name_or_empty();
|
||||
let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
|
||||
if let Some(edition) = edition && edition > features_edition {
|
||||
features_edition = edition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enable edition-dependent features based on `features_edition`.
|
||||
// - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher
|
||||
let mut edition_enabled_features = FxHashSet::default();
|
||||
for feature in active_features_up_to(features_edition) {
|
||||
// FIXME(Manishearth) there is currently no way to set lib features by
|
||||
// edition.
|
||||
edition_enabled_features.insert(feature.name);
|
||||
feature.set(&mut features);
|
||||
}
|
||||
|
||||
// Process all features declared in the code.
|
||||
for attr in krate_attrs {
|
||||
if !attr.has_name(sym::feature) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(list) = attr.meta_item_list() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for mi in list {
|
||||
for mi in feature_list(attr) {
|
||||
let name = match mi.ident() {
|
||||
Some(ident) if mi.is_word() => ident.name,
|
||||
Some(ident) => {
|
||||
@ -136,38 +110,59 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(&edition) = edition_enabled_features.get(&name) {
|
||||
// If the declared feature is an edition umbrella feature-gate,
|
||||
// warn if it was redundant w.r.t. `crate_edition`.
|
||||
// - E.g. warn if `rust_2018_preview` is declared when
|
||||
// `crate_edition` is 2018
|
||||
// - E.g. don't warn if `rust_2018_preview` is declared when
|
||||
// `crate_edition` is 2015.
|
||||
if let Some(&edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
|
||||
if edition <= crate_edition {
|
||||
sess.emit_warning(FeatureIncludedInEdition {
|
||||
span: mi.span(),
|
||||
feature: name,
|
||||
edition,
|
||||
});
|
||||
}
|
||||
features.set_declared_lang_feature(name, mi.span(), None);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the declared feature is edition-dependent and was already
|
||||
// enabled due to `feature_edition`, give a warning.
|
||||
// - E.g. warn if `test_2018_feature` is declared when
|
||||
// `feature_edition` is 2018 or higher.
|
||||
if edition_enabled_features.contains(&name) {
|
||||
sess.emit_warning(FeatureIncludedInEdition {
|
||||
span: mi.span(),
|
||||
feature: name,
|
||||
edition,
|
||||
edition: features_edition,
|
||||
});
|
||||
features.set_declared_lang_feature(name, mi.span(), None);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
|
||||
// Handled in the separate loop above.
|
||||
continue;
|
||||
}
|
||||
|
||||
let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
|
||||
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
|
||||
if let Some(Feature { state, .. }) = removed.or(stable_removed) {
|
||||
if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } =
|
||||
state
|
||||
{
|
||||
feature_removed(sess, mi.span(), *reason);
|
||||
// If the declared feature has been removed, issue an error.
|
||||
if let Some(Feature { state, .. }) = REMOVED_FEATURES.iter().find(|f| name == f.name) {
|
||||
if let FeatureState::Removed { reason } = state {
|
||||
sess.emit_err(FeatureRemoved {
|
||||
span: mi.span(),
|
||||
reason: reason.map(|reason| FeatureRemovedReason { reason }),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If the declared feature is stable, record it.
|
||||
if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
|
||||
let since = Some(Symbol::intern(since));
|
||||
features.declared_lang_features.push((name, mi.span(), since));
|
||||
features.active_features.insert(name);
|
||||
features.set_declared_lang_feature(name, mi.span(), since);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If `-Z allow-features` is used and the declared feature is
|
||||
// unstable and not also listed as one of the allowed features,
|
||||
// issue an error.
|
||||
if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
|
||||
if allowed.iter().all(|f| name.as_str() != f) {
|
||||
sess.emit_err(FeatureNotAllowed { span: mi.span(), name });
|
||||
@ -175,15 +170,16 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
||||
}
|
||||
}
|
||||
|
||||
// If the declared feature is unstable, record it.
|
||||
if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
|
||||
f.set(&mut features, mi.span());
|
||||
features.declared_lang_features.push((name, mi.span(), None));
|
||||
features.active_features.insert(name);
|
||||
f.set(&mut features);
|
||||
features.set_declared_lang_feature(name, mi.span(), None);
|
||||
continue;
|
||||
}
|
||||
|
||||
features.declared_lib_features.push((name, mi.span()));
|
||||
features.active_features.insert(name);
|
||||
// Otherwise, the feature is unknown. Record it as a lib feature.
|
||||
// It will be checked later.
|
||||
features.set_declared_lib_feature(name, mi.span());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,15 +7,6 @@ use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
macro_rules! set {
|
||||
($field: ident) => {{
|
||||
fn f(features: &mut Features, _: Span) {
|
||||
features.$field = true;
|
||||
}
|
||||
f as fn(&mut Features, Span)
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum FeatureStatus {
|
||||
Default,
|
||||
@ -23,16 +14,19 @@ enum FeatureStatus {
|
||||
Internal,
|
||||
}
|
||||
|
||||
macro_rules! declare_features {
|
||||
(__status_to_enum active) => {
|
||||
macro_rules! status_to_enum {
|
||||
(active) => {
|
||||
FeatureStatus::Default
|
||||
};
|
||||
(__status_to_enum incomplete) => {
|
||||
(incomplete) => {
|
||||
FeatureStatus::Incomplete
|
||||
};
|
||||
(__status_to_enum internal) => {
|
||||
(internal) => {
|
||||
FeatureStatus::Internal
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! declare_features {
|
||||
($(
|
||||
$(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr, $edition:expr),
|
||||
)+) => {
|
||||
@ -43,7 +37,10 @@ macro_rules! declare_features {
|
||||
&[$(
|
||||
// (sym::$feature, $ver, $issue, $edition, set!($feature))
|
||||
Feature {
|
||||
state: State::Active { set: set!($feature) },
|
||||
state: State::Active {
|
||||
// Sets this feature's corresponding bool within `features`.
|
||||
set: |features| features.$feature = true,
|
||||
},
|
||||
name: sym::$feature,
|
||||
since: $ver,
|
||||
issue: to_nonzero($issue),
|
||||
@ -58,8 +55,9 @@ macro_rules! declare_features {
|
||||
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
|
||||
/// `#![feature]` attrs for non-language (library) features.
|
||||
pub declared_lib_features: Vec<(Symbol, Span)>,
|
||||
/// Features enabled for this crate.
|
||||
pub active_features: FxHashSet<Symbol>,
|
||||
/// `declared_lang_features` + `declared_lib_features`.
|
||||
pub declared_features: FxHashSet<Symbol>,
|
||||
/// Individual features (unstable only).
|
||||
$(
|
||||
$(#[doc = $doc])*
|
||||
pub $feature: bool
|
||||
@ -67,16 +65,33 @@ macro_rules! declare_features {
|
||||
}
|
||||
|
||||
impl Features {
|
||||
pub fn set_declared_lang_feature(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
span: Span,
|
||||
since: Option<Symbol>
|
||||
) {
|
||||
self.declared_lang_features.push((symbol, span, since));
|
||||
self.declared_features.insert(symbol);
|
||||
}
|
||||
|
||||
pub fn set_declared_lib_feature(&mut self, symbol: Symbol, span: Span) {
|
||||
self.declared_lib_features.push((symbol, span));
|
||||
self.declared_features.insert(symbol);
|
||||
}
|
||||
|
||||
pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) {
|
||||
$(f(stringify!($feature), self.$feature);)+
|
||||
}
|
||||
|
||||
/// Is the given feature active?
|
||||
pub fn active(&self, feature: Symbol) -> bool {
|
||||
self.active_features.contains(&feature)
|
||||
/// Is the given feature explicitly declared, i.e. named in a
|
||||
/// `#![feature(...)]` within the code?
|
||||
pub fn declared(&self, feature: Symbol) -> bool {
|
||||
self.declared_features.contains(&feature)
|
||||
}
|
||||
|
||||
/// Is the given feature enabled?
|
||||
/// Is the given feature enabled, i.e. declared or automatically
|
||||
/// enabled due to the edition?
|
||||
///
|
||||
/// Panics if the symbol doesn't correspond to a declared feature.
|
||||
pub fn enabled(&self, feature: Symbol) -> bool {
|
||||
@ -93,11 +108,10 @@ macro_rules! declare_features {
|
||||
pub fn incomplete(&self, feature: Symbol) -> bool {
|
||||
match feature {
|
||||
$(
|
||||
sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Incomplete,
|
||||
sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete,
|
||||
)*
|
||||
// accepted and removed features aren't in this file but are never incomplete
|
||||
_ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false,
|
||||
_ if self.declared_lib_features.iter().any(|f| f.0 == feature) => false,
|
||||
_ if self.declared_features.contains(&feature) => false,
|
||||
_ => panic!("`{}` was not listed in `declare_features`", feature),
|
||||
}
|
||||
}
|
||||
@ -108,12 +122,11 @@ macro_rules! declare_features {
|
||||
pub fn internal(&self, feature: Symbol) -> bool {
|
||||
match feature {
|
||||
$(
|
||||
sym::$feature => declare_features!(__status_to_enum $status) == FeatureStatus::Internal,
|
||||
sym::$feature => status_to_enum!($status) == FeatureStatus::Internal,
|
||||
)*
|
||||
// accepted and removed features aren't in this file but are never internal
|
||||
// (a removed feature might have been internal, but it doesn't matter anymore)
|
||||
_ if self.declared_lang_features.iter().any(|f| f.0 == feature) => false,
|
||||
_ if self.declared_lib_features.iter().any(|f| f.0 == feature) => false,
|
||||
_ if self.declared_features.contains(&feature) => false,
|
||||
_ => panic!("`{}` was not listed in `declare_features`", feature),
|
||||
}
|
||||
}
|
||||
@ -123,9 +136,9 @@ macro_rules! declare_features {
|
||||
|
||||
impl Feature {
|
||||
/// Sets this feature in `Features`. Panics if called on a non-active feature.
|
||||
pub fn set(&self, features: &mut Features, span: Span) {
|
||||
pub fn set(&self, features: &mut Features) {
|
||||
match self.state {
|
||||
State::Active { set } => set(features, span),
|
||||
State::Active { set } => set(features),
|
||||
_ => panic!("called `set` on feature `{}` which is not `active`", self.name),
|
||||
}
|
||||
}
|
||||
|
@ -23,16 +23,15 @@ mod removed;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use rustc_span::{edition::Edition, symbol::Symbol, Span};
|
||||
use rustc_span::{edition::Edition, symbol::Symbol};
|
||||
use std::fmt;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum State {
|
||||
Accepted,
|
||||
Active { set: fn(&mut Features, Span) },
|
||||
Active { set: fn(&mut Features) },
|
||||
Removed { reason: Option<&'static str> },
|
||||
Stabilized { reason: Option<&'static str> },
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
@ -41,7 +40,6 @@ impl fmt::Debug for State {
|
||||
State::Accepted { .. } => write!(f, "accepted"),
|
||||
State::Active { .. } => write!(f, "active"),
|
||||
State::Removed { .. } => write!(f, "removed"),
|
||||
State::Stabilized { .. } => write!(f, "stabilized"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,8 +77,8 @@ pub enum UnstableFeatures {
|
||||
impl UnstableFeatures {
|
||||
/// This takes into account `RUSTC_BOOTSTRAP`.
|
||||
///
|
||||
/// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly features.
|
||||
/// Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
|
||||
/// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly
|
||||
/// features. Otherwise, only `RUSTC_BOOTSTRAP=1` will work.
|
||||
pub fn from_environment(krate: Option<&str>) -> Self {
|
||||
// `true` if this is a feature-staged build, i.e., on the beta or stable channel.
|
||||
let disable_unstable_features =
|
||||
@ -107,19 +105,17 @@ impl UnstableFeatures {
|
||||
}
|
||||
|
||||
fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
|
||||
if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
|
||||
info.issue
|
||||
} else {
|
||||
// search in Accepted, Removed, or Stable Removed features
|
||||
let found = ACCEPTED_FEATURES
|
||||
.iter()
|
||||
.chain(REMOVED_FEATURES)
|
||||
.chain(STABLE_REMOVED_FEATURES)
|
||||
.find(|t| t.name == feature);
|
||||
match found {
|
||||
Some(found) => found.issue,
|
||||
None => panic!("feature `{feature}` is not declared anywhere"),
|
||||
}
|
||||
// Search in all the feature lists.
|
||||
let found = []
|
||||
.iter()
|
||||
.chain(ACTIVE_FEATURES)
|
||||
.chain(ACCEPTED_FEATURES)
|
||||
.chain(REMOVED_FEATURES)
|
||||
.find(|t| t.name == feature);
|
||||
|
||||
match found {
|
||||
Some(found) => found.issue,
|
||||
None => panic!("feature `{feature}` is not declared anywhere"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,4 +148,4 @@ pub use builtin_attrs::{
|
||||
is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute,
|
||||
GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
|
||||
};
|
||||
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
|
||||
pub use removed::REMOVED_FEATURES;
|
||||
|
@ -20,23 +20,6 @@ macro_rules! declare_features {
|
||||
),+
|
||||
];
|
||||
};
|
||||
|
||||
($(
|
||||
$(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None),
|
||||
)+) => {
|
||||
/// Represents stable features which have since been removed (it was once Accepted)
|
||||
pub const STABLE_REMOVED_FEATURES: &[Feature] = &[
|
||||
$(
|
||||
Feature {
|
||||
state: State::Stabilized { reason: None },
|
||||
name: sym::$feature,
|
||||
since: $ver,
|
||||
issue: to_nonzero($issue),
|
||||
edition: None,
|
||||
}
|
||||
),+
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
@ -141,6 +124,11 @@ declare_features! (
|
||||
(removed, no_coverage, "CURRENT_RUSTC_VERSION", Some(84605), None, Some("renamed to `coverage_attribute`")),
|
||||
/// Allows `#[no_debug]`.
|
||||
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
|
||||
/// Note: this feature was previously recorded in a separate
|
||||
/// `STABLE_REMOVED` list because it, uniquely, was once stable but was
|
||||
/// then removed. But there was no utility storing it separately, so now
|
||||
/// it's in this list.
|
||||
(removed, no_stack_check, "1.0.0", None, None, None),
|
||||
/// Allows using `#[on_unimplemented(..)]` on traits.
|
||||
/// (Moved to `rustc_attrs`.)
|
||||
(removed, on_unimplemented, "1.40.0", None, None, None),
|
||||
@ -208,8 +196,3 @@ declare_features! (
|
||||
// feature-group-end: removed features
|
||||
// -------------------------------------------------------------------------
|
||||
);
|
||||
|
||||
#[rustfmt::skip]
|
||||
declare_features! (
|
||||
(stable_removed, no_stack_check, "1.0.0", None, None),
|
||||
);
|
||||
|
@ -448,14 +448,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
debug!("stability: skipping span={:?} since it is internal", span);
|
||||
return EvalResult::Allow;
|
||||
}
|
||||
if self.features().active(feature) {
|
||||
if self.features().declared(feature) {
|
||||
return EvalResult::Allow;
|
||||
}
|
||||
|
||||
// If this item was previously part of a now-stabilized feature which is still
|
||||
// active (i.e. the user hasn't removed the attribute for the stabilized feature
|
||||
// yet) then allow use of this item.
|
||||
if let Some(implied_by) = implied_by && self.features().active(implied_by) {
|
||||
if let Some(implied_by) = implied_by && self.features().declared(implied_by) {
|
||||
return EvalResult::Allow;
|
||||
}
|
||||
|
||||
@ -532,7 +532,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
debug!("body stability: skipping span={:?} since it is internal", span);
|
||||
return EvalResult::Allow;
|
||||
}
|
||||
if self.features().active(feature) {
|
||||
if self.features().declared(feature) {
|
||||
return EvalResult::Allow;
|
||||
}
|
||||
|
||||
|
@ -1074,8 +1074,8 @@ pub struct Resolver<'a, 'tcx> {
|
||||
/// Also includes of list of each fields visibility
|
||||
struct_constructors: LocalDefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
|
||||
|
||||
/// Features enabled for this crate.
|
||||
active_features: FxHashSet<Symbol>,
|
||||
/// Features declared for this crate.
|
||||
declared_features: FxHashSet<Symbol>,
|
||||
|
||||
lint_buffer: LintBuffer,
|
||||
|
||||
@ -1417,12 +1417,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
multi_segment_macro_resolutions: Default::default(),
|
||||
builtin_attrs: Default::default(),
|
||||
containers_deriving_copy: Default::default(),
|
||||
active_features: features
|
||||
.declared_lib_features
|
||||
.iter()
|
||||
.map(|(feat, ..)| *feat)
|
||||
.chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
|
||||
.collect(),
|
||||
declared_features: features.declared_features.clone(),
|
||||
lint_buffer: LintBuffer::default(),
|
||||
next_node_id: CRATE_NODE_ID,
|
||||
node_id_to_def_id,
|
||||
|
@ -854,7 +854,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
let feature = stability.feature;
|
||||
|
||||
let is_allowed = |feature| {
|
||||
self.active_features.contains(&feature) || span.allows_unstable(feature)
|
||||
self.declared_features.contains(&feature) || span.allows_unstable(feature)
|
||||
};
|
||||
let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
|
||||
if !is_allowed(feature) && !allowed_by_implication {
|
||||
|
@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
||||
if !in_external_macro(cx.sess(), expr.span)
|
||||
&& (
|
||||
matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
|
||||
|| cx.tcx.features().active(sym!(const_float_classify))
|
||||
|| cx.tcx.features().declared(sym!(const_float_classify))
|
||||
) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
|
||||
&& let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
|
||||
&& let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
|
||||
|
Loading…
Reference in New Issue
Block a user