Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
}
}

Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend))
let linker = Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend);

tcx.report_unused_features();

Some(linker)
});

// Linking is done outside the `compiler.enter()` so that the
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
#![allow(rustc::direct_use_of_rustc_type_ir)]
#![cfg_attr(bootstrap, feature(assert_matches))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(default_field_values)]
#![feature(error_reporter)]
#![feature(macro_metavar_expr_concat)]
#![feature(negative_impls)]
#![feature(never_type)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1330,7 +1330,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
safety: AttributeSafety::Normal,
template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing,
gate: Gated{
gate: Gated {
feature: sym::rustc_attrs,
message: "use of an internal attribute",
check: Features::rustc_attrs,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,5 @@ pub use builtin_attrs::{
pub use removed::REMOVED_LANG_FEATURES;
pub use unstable::{
DEPENDENT_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES,
UNSTABLE_LANG_FEATURES,
TRACK_FEATURE, UNSTABLE_LANG_FEATURES,
};
16 changes: 14 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};

use rustc_data_structures::AtomicRef;
use rustc_data_structures::fx::FxHashSet;
use rustc_span::{Span, Symbol, sym};

use super::{Feature, to_nonzero};

fn default_track_feature(_: Symbol) {}

/// Recording used features in the dependency graph so incremental can
/// replay used features when needed.
pub static TRACK_FEATURE: AtomicRef<fn(Symbol)> = AtomicRef::new(&(default_track_feature as _));

#[derive(PartialEq)]
enum FeatureStatus {
Default,
Expand Down Expand Up @@ -103,7 +110,12 @@ impl Features {

/// Is the given feature enabled (via `#[feature(...)]`)?
pub fn enabled(&self, feature: Symbol) -> bool {
self.enabled_features.contains(&feature)
if self.enabled_features.contains(&feature) {
TRACK_FEATURE(feature);
true
} else {
false
}
}
}

Expand All @@ -124,7 +136,7 @@ macro_rules! declare_features {
impl Features {
$(
pub fn $feature(&self) -> bool {
self.enabled_features.contains(&sym::$feature)
self.enabled(sym::$feature)
}
)*

Expand Down
23 changes: 22 additions & 1 deletion compiler/rustc_interface/src/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
use std::fmt;

use rustc_errors::DiagInner;
use rustc_middle::dep_graph::TaskDepsRef;
use rustc_middle::dep_graph::{DepNodeIndex, QuerySideEffect, TaskDepsRef};
use rustc_middle::ty::tls;
use rustc_span::Symbol;

fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
tls::with_context_opt(|icx| {
Expand Down Expand Up @@ -51,6 +52,25 @@ fn track_diagnostic<R>(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner) -> R)
})
}

fn track_feature(feature: Symbol) {
tls::with_context_opt(|icx| {
let Some(icx) = icx else {
return;
};
let tcx = icx.tcx;

if let Some(dep_node_index) = tcx.sess.used_features.lock().get(&feature).copied() {
tcx.dep_graph.read_index(DepNodeIndex::from_u32(dep_node_index));
} else {
let dep_node_index = tcx
.dep_graph
.encode_side_effect(tcx, QuerySideEffect::CheckFeature { symbol: feature });
tcx.sess.used_features.lock().insert(feature, dep_node_index.as_u32());
tcx.dep_graph.read_index(dep_node_index);
}
})
}

/// This is a callback from `rustc_hir` as it cannot access the implicit state
/// in `rustc_middle` otherwise.
fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -70,4 +90,5 @@ pub fn setup_callbacks() {
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
rustc_errors::TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
rustc_feature::TRACK_FEATURE.swap(&(track_feature as _));
}
5 changes: 0 additions & 5 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,11 +1088,6 @@ declare_lint! {
/// crate-level [`feature` attributes].
///
/// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/
///
/// Note: This lint is currently not functional, see [issue #44232] for
/// more details.
///
/// [issue #44232]: https://github.com/rust-lang/rust/issues/44232
pub UNUSED_FEATURES,
Warn,
"unused features found in crate-level `#[feature]` directives"
Expand Down
72 changes: 48 additions & 24 deletions compiler/rustc_middle/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::Session;
use rustc_span::Symbol;
use tracing::{debug, instrument};
#[cfg(debug_assertions)]
use {super::debug::EdgeFilter, std::env};
Expand Down Expand Up @@ -45,6 +46,11 @@ pub enum QuerySideEffect {
/// the query as green, as that query will have the side
/// effect dep node as a dependency.
Diagnostic(DiagInner),
/// Records the feature used during query execution.
/// This feature will be inserted into `sess.used_features`
/// if we mark the query as green, as that query will have
/// the side effect dep node as a dependency.
CheckFeature { symbol: Symbol },
}
#[derive(Clone)]
pub struct DepGraph {
Expand Down Expand Up @@ -514,29 +520,40 @@ impl DepGraph {
}
}

/// This encodes a diagnostic by creating a node with an unique index and associating
/// `diagnostic` with it, for use in the next session.
/// This encodes a side effect by creating a node with an unique index and associating
/// it with the node, for use in the next session.
#[inline]
pub fn record_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) {
if let Some(ref data) = self.data {
read_deps(|task_deps| match task_deps {
TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return,
TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => {
self.read_index(data.encode_diagnostic(tcx, diagnostic));
let dep_node_index = data
.encode_side_effect(tcx, QuerySideEffect::Diagnostic(diagnostic.clone()));
self.read_index(dep_node_index);
}
})
}
}
/// This forces a diagnostic node green by running its side effect. `prev_index` would
/// refer to a node created used `encode_diagnostic` in the previous session.
/// This forces a side effect node green by running its side effect. `prev_index` would
/// refer to a node created used `encode_side_effect` in the previous session.
#[inline]
pub fn force_diagnostic_node<'tcx>(
pub fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) {
if let Some(ref data) = self.data {
data.force_side_effect(tcx, prev_index);
}
}

#[inline]
pub fn encode_side_effect<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
prev_index: SerializedDepNodeIndex,
) {
side_effect: QuerySideEffect,
) -> DepNodeIndex {
if let Some(ref data) = self.data {
data.force_diagnostic_node(tcx, prev_index);
data.encode_side_effect(tcx, side_effect)
} else {
self.next_virtual_depnode_index()
}
}

Expand Down Expand Up @@ -673,39 +690,36 @@ impl DepGraphData {
self.debug_loaded_from_disk.lock().insert(dep_node);
}

/// This encodes a diagnostic by creating a node with an unique index and associating
/// `diagnostic` with it, for use in the next session.
/// This encodes a side effect by creating a node with an unique index and associating
/// it with the node, for use in the next session.
#[inline]
fn encode_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) -> DepNodeIndex {
fn encode_side_effect<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
side_effect: QuerySideEffect,
) -> DepNodeIndex {
// Use `send_new` so we get an unique index, even though the dep node is not.
let dep_node_index = self.current.encoder.send_new(
DepNode {
kind: DepKind::SideEffect,
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
Fingerprint::ZERO,
// We want the side effect node to always be red so it will be forced and emit the
// diagnostic.
// We want the side effect node to always be red so it will be forced and run the
// side effect.
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
);
let side_effect = QuerySideEffect::Diagnostic(diagnostic.clone());
tcx.store_side_effect(dep_node_index, side_effect);
dep_node_index
}

/// This forces a diagnostic node green by running its side effect. `prev_index` would
/// refer to a node created used `encode_diagnostic` in the previous session.
/// This forces a side effect node green by running its side effect. `prev_index` would
/// refer to a node created used `encode_side_effect` in the previous session.
#[inline]
fn force_diagnostic_node<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) {
fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) {
with_deps(TaskDepsRef::Ignore, || {
let side_effect = tcx.load_side_effect(prev_index).unwrap();

match &side_effect {
QuerySideEffect::Diagnostic(diagnostic) => {
tcx.dcx().emit_diagnostic(diagnostic.clone());
}
}

// Use `send_and_color` as `promote_node_and_deps_to_current` expects all
// green dependencies. `send_and_color` will also prevent multiple nodes
// being encoded for concurrent calls.
Expand All @@ -720,6 +734,16 @@ impl DepGraphData {
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
true,
);

match &side_effect {
QuerySideEffect::Diagnostic(diagnostic) => {
tcx.dcx().emit_diagnostic(diagnostic.clone());
}
QuerySideEffect::CheckFeature { symbol } => {
tcx.sess.used_features.lock().insert(*symbol, dep_node_index.as_u32());
}
}

// This will just overwrite the same value for concurrent calls.
tcx.store_side_effect(dep_node_index, side_effect);
})
Expand Down
32 changes: 31 additions & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::lang_items::LangItem;
use rustc_hir::limit::Limit;
use rustc_hir::{self as hir, HirId, Node, TraitCandidate, find_attr};
use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr};
use rustc_index::IndexVec;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::Session;
Expand Down Expand Up @@ -1688,6 +1688,36 @@ impl<'tcx> TyCtxt<'tcx> {
self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error });
}
}

pub fn report_unused_features(self) {
// Collect first to avoid holding the lock while linting.
let used_features = self.sess.used_features.lock();
let unused_features = self
.features()
.enabled_features_iter_stable_order()
.filter(|(f, _)| {
!used_features.contains_key(f)
// FIXME: `restricted_std` is used to tell a standard library built
// for a platform that it doesn't know how to support. But it
// could only gate a private mod (see `__restricted_std_workaround`)
// with `cfg(not(restricted_std))`, so it cannot be recorded as used
// in downstream crates. It should never be linted, but should we
// hack this in the linter to ignore it?
&& f.as_str() != "restricted_std"
})
.collect::<Vec<_>>();

for (feature, span) in unused_features {
self.node_span_lint(
rustc_session::lint::builtin::UNUSED_FEATURES,
CRATE_HIR_ID,
span,
|lint| {
lint.primary_message(format!("feature `{}` is declared but not used", feature));
},
);
}
}
}

macro_rules! nop_lift {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_query_impl/src/dep_kind_vtables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ mod non_query {
is_eval_always: false,
key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node_fn: Some(|tcx, _, prev_index| {
tcx.dep_graph.force_diagnostic_node(tcx, prev_index);
tcx.dep_graph.force_side_effect(tcx, prev_index);
true
}),
promote_from_disk_fn: None,
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ pub struct Session {
/// Used by `-Zmir-opt-bisect-limit` to assign an index to each
/// optimization-pass execution candidate during this compilation.
pub mir_opt_bisect_eval_count: AtomicUsize,

/// Enabled features that are used in the current compilation.
///
/// The value is the `DepNodeIndex` of the node encodes the used feature.
pub used_features: Lock<FxHashMap<Symbol, u32>>,
}

#[derive(Clone, Copy)]
Expand Down Expand Up @@ -1096,6 +1101,7 @@ pub fn build_session(
replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler`
thin_lto_supported: true, // filled by `run_compiler`
mir_opt_bisect_eval_count: AtomicUsize::new(0),
used_features: Lock::default(),
};

validate_commandline_args_with_session_available(&sess);
Expand Down
1 change: 0 additions & 1 deletion library/alloctests/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#![feature(allocator_api)]
#![feature(binary_heap_pop_if)]
#![feature(btree_merge)]
#![feature(const_heap)]
#![feature(deque_extend_front)]
#![feature(iter_array_chunks)]
Expand Down
6 changes: 5 additions & 1 deletion library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1521,7 +1521,11 @@ impl f16 {
// Functions in this module fall into `core_float_math`
// #[unstable(feature = "core_float_math", issue = "137578")]
#[cfg(not(test))]
#[doc(test(attr(feature(cfg_target_has_reliable_f16_f128), expect(internal_features))))]
#[doc(test(attr(
feature(cfg_target_has_reliable_f16_f128),
expect(internal_features),
allow(unused_features)
)))]
impl f16 {
/// Returns the largest integer less than or equal to `self`.
///
Expand Down
1 change: 1 addition & 0 deletions library/core/src/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ pub mod consts {
pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32;
}

#[doc(test(attr(allow(unused_features))))]
impl f32 {
/// The radix or base of the internal representation of `f32`.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
Expand Down
1 change: 1 addition & 0 deletions library/core/src/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ pub mod consts {
pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64;
}

#[doc(test(attr(allow(unused_features))))]
impl f64 {
/// The radix or base of the internal representation of `f64`.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
Expand Down
1 change: 0 additions & 1 deletion library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
#![feature(f16)]
#![feature(f128)]
#![feature(float_algebraic)]
#![feature(float_bits_const)]
#![feature(float_exact_integer_constants)]
#![feature(float_gamma)]
#![feature(float_minimum_maximum)]
Expand Down
Loading
Loading