Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge unused_tuple_struct_fields into dead_code #118297

Merged
merged 8 commits into from Jan 5, 2024
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Expand Up @@ -328,6 +328,7 @@ fn register_builtins(store: &mut LintStore) {
store.register_renamed("disjoint_capture_migration", "rust_2021_incompatible_closure_captures");
store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns");
store.register_renamed("non_fmt_panic", "non_fmt_panics");
store.register_renamed("unused_tuple_struct_fields", "dead_code");

// These were moved to tool lints, but rustc still sees them when compiling normally, before
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
Expand Down
36 changes: 7 additions & 29 deletions compiler/rustc_lint_defs/src/builtin.rs
Expand Up @@ -125,7 +125,6 @@ declare_lint_pass! {
UNUSED_MACROS,
UNUSED_MUT,
UNUSED_QUALIFICATIONS,
UNUSED_TUPLE_STRUCT_FIELDS,
UNUSED_UNSAFE,
UNUSED_VARIABLES,
USELESS_DEPRECATED,
Expand Down Expand Up @@ -697,8 +696,13 @@ declare_lint! {
/// Dead code may signal a mistake or unfinished code. To silence the
/// warning for individual items, prefix the name with an underscore such
/// as `_foo`. If it was intended to expose the item outside of the crate,
/// consider adding a visibility modifier like `pub`. Otherwise consider
/// removing the unused code.
/// consider adding a visibility modifier like `pub`.
///
/// To preserve the numbering of tuple structs with unused fields,
/// change the unused fields to have unit type or use
/// `PhantomData`.
///
/// Otherwise consider removing the unused code.
pub DEAD_CODE,
Warn,
"detect unused, unexported items"
Expand Down Expand Up @@ -732,32 +736,6 @@ declare_lint! {
"detects attributes that were not used by the compiler"
}

declare_lint! {
/// The `unused_tuple_struct_fields` lint detects fields of tuple structs
/// that are never read.
///
/// ### Example
///
/// ```rust
/// #[warn(unused_tuple_struct_fields)]
/// struct S(i32, i32, i32);
/// let s = S(1, 2, 3);
/// let _ = (s.0, s.2);
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Tuple struct fields that are never read anywhere may indicate a
/// mistake or unfinished code. To silence this warning, consider
/// removing the unused field(s) or, to preserve the numbering of the
/// remaining fields, change the unused field(s) to have unit type.
pub UNUSED_TUPLE_STRUCT_FIELDS,
Allow,
"detects tuple struct fields that are never read"
}

declare_lint! {
/// The `unreachable_code` lint detects unreachable code paths.
///
Expand Down
58 changes: 35 additions & 23 deletions compiler/rustc_passes/src/dead.rs
Expand Up @@ -15,8 +15,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::privacy::Level;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{DEAD_CODE, UNUSED_TUPLE_STRUCT_FIELDS};
use rustc_session::lint::{self, Lint, LintId};
use rustc_session::lint;
use rustc_session::lint::builtin::DEAD_CODE;
use rustc_span::symbol::{sym, Symbol};
use rustc_target::abi::FieldIdx;
use std::mem;
Expand Down Expand Up @@ -766,6 +766,12 @@ enum ShouldWarnAboutField {
No,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ReportOn {
TupleField,
NamedField,
}

impl<'tcx> DeadVisitor<'tcx> {
fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> ShouldWarnAboutField {
if self.live_symbols.contains(&field.did.expect_local()) {
Expand All @@ -787,9 +793,9 @@ impl<'tcx> DeadVisitor<'tcx> {
ShouldWarnAboutField::Yes
}

fn def_lint_level(&self, lint: &'static Lint, id: LocalDefId) -> lint::Level {
fn def_lint_level(&self, id: LocalDefId) -> lint::Level {
let hir_id = self.tcx.local_def_id_to_hir_id(id);
self.tcx.lint_level_at_node(lint, hir_id).0
self.tcx.lint_level_at_node(DEAD_CODE, hir_id).0
}

// # Panics
Expand All @@ -803,7 +809,7 @@ impl<'tcx> DeadVisitor<'tcx> {
dead_codes: &[&DeadItem],
participle: &str,
parent_item: Option<LocalDefId>,
lint: &'static Lint,
report_on: ReportOn,
) {
let Some(&first_item) = dead_codes.first() else {
return;
Expand Down Expand Up @@ -864,8 +870,8 @@ impl<'tcx> DeadVisitor<'tcx> {
None
};

let diag = if LintId::of(lint) == LintId::of(UNUSED_TUPLE_STRUCT_FIELDS) {
MultipleDeadCodes::UnusedTupleStructFields {
let diag = match report_on {
ReportOn::TupleField => MultipleDeadCodes::UnusedTupleStructFields {
multiple,
num,
descr,
Expand All @@ -874,29 +880,29 @@ impl<'tcx> DeadVisitor<'tcx> {
change_fields_suggestion: ChangeFieldsToBeOfUnitType { num, spans: spans.clone() },
parent_info,
ignored_derived_impls,
}
} else {
MultipleDeadCodes::DeadCodes {
},

ReportOn::NamedField => MultipleDeadCodes::DeadCodes {
multiple,
num,
descr,
participle,
name_list,
parent_info,
ignored_derived_impls,
}
},
};

let hir_id = tcx.local_def_id_to_hir_id(first_item.def_id);
self.tcx.emit_spanned_lint(lint, hir_id, MultiSpan::from_spans(spans), diag);
self.tcx.emit_spanned_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag);
}

fn warn_multiple(
&self,
def_id: LocalDefId,
participle: &str,
dead_codes: Vec<DeadItem>,
lint: &'static Lint,
report_on: ReportOn,
) {
let mut dead_codes = dead_codes
.iter()
Expand All @@ -907,17 +913,17 @@ impl<'tcx> DeadVisitor<'tcx> {
}
dead_codes.sort_by_key(|v| v.level);
for group in dead_codes[..].group_by(|a, b| a.level == b.level) {
self.lint_at_single_level(&group, participle, Some(def_id), lint);
self.lint_at_single_level(&group, participle, Some(def_id), report_on);
}
}

fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) {
let item = DeadItem {
def_id: id,
name: self.tcx.item_name(id.to_def_id()),
level: self.def_lint_level(DEAD_CODE, id),
level: self.def_lint_level(id),
};
self.lint_at_single_level(&[&item], participle, None, DEAD_CODE);
self.lint_at_single_level(&[&item], participle, None, ReportOn::NamedField);
}

fn check_definition(&mut self, def_id: LocalDefId) {
Expand Down Expand Up @@ -964,12 +970,12 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
let def_id = item.id.owner_id.def_id;
if !visitor.is_live_code(def_id) {
let name = tcx.item_name(def_id.to_def_id());
let level = visitor.def_lint_level(DEAD_CODE, def_id);
let level = visitor.def_lint_level(def_id);

dead_items.push(DeadItem { def_id, name, level })
}
}
visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, DEAD_CODE);
visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, ReportOn::NamedField);
}

if !live_symbols.contains(&item.owner_id.def_id) {
Expand All @@ -991,32 +997,38 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
let def_id = variant.def_id.expect_local();
if !live_symbols.contains(&def_id) {
// Record to group diagnostics.
let level = visitor.def_lint_level(DEAD_CODE, def_id);
let level = visitor.def_lint_level(def_id);
dead_variants.push(DeadItem { def_id, name: variant.name, level });
continue;
}

let is_positional = variant.fields.raw.first().map_or(false, |field| {
field.name.as_str().starts_with(|c: char| c.is_ascii_digit())
});
let lint = if is_positional { UNUSED_TUPLE_STRUCT_FIELDS } else { DEAD_CODE };
let report_on =
if is_positional { ReportOn::TupleField } else { ReportOn::NamedField };
let dead_fields = variant
.fields
.iter()
.filter_map(|field| {
let def_id = field.did.expect_local();
if let ShouldWarnAboutField::Yes = visitor.should_warn_about_field(field) {
let level = visitor.def_lint_level(lint, def_id);
let level = visitor.def_lint_level(def_id);
Some(DeadItem { def_id, name: field.name, level })
} else {
None
}
})
.collect();
visitor.warn_multiple(def_id, "read", dead_fields, lint);
visitor.warn_multiple(def_id, "read", dead_fields, report_on);
}

visitor.warn_multiple(item.owner_id.def_id, "constructed", dead_variants, DEAD_CODE);
visitor.warn_multiple(
item.owner_id.def_id,
"constructed",
dead_variants,
ReportOn::NamedField,
);
}
}

Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/boxed.rs
Expand Up @@ -24,6 +24,7 @@
//! Creating a recursive data structure:
//!
//! ```
//! ##[allow(dead_code)]
//! #[derive(Debug)]
//! enum List<T> {
//! Cons(T, Box<List<T>>),
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/boxed/thin.rs
Expand Up @@ -171,7 +171,7 @@ struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
/// An opaque representation of `WithHeader<H>` to avoid the
/// projection invariance of `<T as Pointee>::Metadata`.
#[repr(transparent)]
#[allow(unused_tuple_struct_fields)] // Field only used through `WithHeader` type above.
#[allow(dead_code)] // Field only used through `WithHeader` type above.
struct WithOpaqueHeader(NonNull<u8>);

impl WithOpaqueHeader {
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/collections/btree/set/tests.rs
Expand Up @@ -524,7 +524,7 @@ fn test_extend_ref() {
#[test]
fn test_recovery() {
#[derive(Debug)]
struct Foo(&'static str, i32);
struct Foo(&'static str, #[allow(dead_code)] i32);

impl PartialEq for Foo {
fn eq(&self, other: &Self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/collections/vec_deque/tests.rs
Expand Up @@ -1085,7 +1085,7 @@ fn test_clone_from() {
fn test_vec_deque_truncate_drop() {
static mut DROPS: u32 = 0;
#[derive(Clone)]
struct Elem(i32);
struct Elem(#[allow(dead_code)] i32);
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/tests/autotraits.rs
@@ -1,7 +1,7 @@
fn require_sync<T: Sync>(_: T) {}
fn require_send_sync<T: Send + Sync>(_: T) {}

struct NotSend(*const ());
struct NotSend(#[allow(dead_code)] *const ());
unsafe impl Sync for NotSend {}

#[test]
Expand Down
6 changes: 3 additions & 3 deletions library/alloc/tests/vec.rs
Expand Up @@ -547,7 +547,7 @@ fn test_cmp() {
#[test]
fn test_vec_truncate_drop() {
static mut DROPS: u32 = 0;
struct Elem(i32);
struct Elem(#[allow(dead_code)] i32);
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
Expand Down Expand Up @@ -1089,7 +1089,7 @@ fn test_into_iter_advance_by() {

#[test]
fn test_into_iter_drop_allocator() {
struct ReferenceCountedAllocator<'a>(DropCounter<'a>);
struct ReferenceCountedAllocator<'a>(#[allow(dead_code)] DropCounter<'a>);

unsafe impl Allocator for ReferenceCountedAllocator<'_> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
Expand Down Expand Up @@ -2407,7 +2407,7 @@ fn test_vec_dedup_multiple_ident() {
#[test]
fn test_vec_dedup_partialeq() {
#[derive(Debug)]
struct Foo(i32, i32);
struct Foo(i32, #[allow(dead_code)] i32);

impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions library/core/benches/slice.rs
Expand Up @@ -91,7 +91,7 @@ fn binary_search_l3_worst_case(b: &mut Bencher) {
}

#[derive(Clone)]
struct Rgb(u8, u8, u8);
struct Rgb(#[allow(dead_code)] u8, #[allow(dead_code)] u8, #[allow(dead_code)] u8);

impl Rgb {
fn gen(i: usize) -> Self {
Expand Down Expand Up @@ -154,7 +154,7 @@ swap_with_slice!(swap_with_slice_5x_usize_3000, 3000, |i| [i; 5]);
#[bench]
fn fill_byte_sized(b: &mut Bencher) {
#[derive(Copy, Clone)]
struct NewType(u8);
struct NewType(#[allow(dead_code)] u8);

let mut ary = [NewType(0); 1024];

Expand Down
2 changes: 1 addition & 1 deletion library/core/tests/any.rs
Expand Up @@ -122,7 +122,7 @@ fn any_unsized() {
fn distinct_type_names() {
// https://github.com/rust-lang/rust/issues/84666

struct Velocity(f32, f32);
struct Velocity(#[allow(dead_code)] f32, #[allow(dead_code)] f32);

fn type_name_of_val<T>(_: T) -> &'static str {
type_name::<T>()
Expand Down
2 changes: 1 addition & 1 deletion library/core/tests/array.rs
Expand Up @@ -262,7 +262,7 @@ fn array_default_impl_avoids_leaks_on_panic() {
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
static COUNTER: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug)]
struct Bomb(usize);
struct Bomb(#[allow(dead_code)] usize);

impl Default for Bomb {
fn default() -> Bomb {
Expand Down
2 changes: 1 addition & 1 deletion library/core/tests/atomic.rs
Expand Up @@ -188,7 +188,7 @@ fn ptr_bitops() {
#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
fn ptr_bitops_tagging() {
#[repr(align(16))]
struct Tagme(u128);
struct Tagme(#[allow(dead_code)] u128);

let tagme = Tagme(1000);
let ptr = &tagme as *const Tagme as *mut Tagme;
Expand Down
6 changes: 3 additions & 3 deletions library/core/tests/intrinsics.rs
Expand Up @@ -4,7 +4,7 @@ use core::intrinsics::assume;
#[test]
fn test_typeid_sized_types() {
struct X;
struct Y(u32);
struct Y(#[allow(dead_code)] u32);

assert_eq!(TypeId::of::<X>(), TypeId::of::<X>());
assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>());
Expand All @@ -14,8 +14,8 @@ fn test_typeid_sized_types() {
#[test]
fn test_typeid_unsized_types() {
trait Z {}
struct X(str);
struct Y(dyn Z + 'static);
struct X(#[allow(dead_code)] str);
struct Y(#[allow(dead_code)] dyn Z + 'static);

assert_eq!(TypeId::of::<X>(), TypeId::of::<X>());
assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>());
Expand Down