Rollup merge of #147994 - jdonszelmann:duplicate-warning-struct, r=petrochenkov

Deduplicate deprecation warning when using unit or tuple structs

First commit adds a test that's broken currently, 2nd commit fixes it.

Created with `@WaffleLapkin`
This commit is contained in:
Matthias Krüger 2025-11-05 21:28:27 +01:00 committed by GitHub
commit a508f6136a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 156 additions and 2 deletions

View file

@ -12,8 +12,8 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{
self as hir, AmbigArg, ConstStability, DefaultBodyStability, FieldDef, Item, ItemKind,
Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason,
self as hir, AmbigArg, ConstStability, DefaultBodyStability, FieldDef, HirId, Item, ItemKind,
Path, Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason, UsePath,
VERSION_PLACEHOLDER, Variant, find_attr,
};
use rustc_middle::hir::nested_filter;
@ -739,6 +739,35 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
intravisit::walk_poly_trait_ref(self, t);
}
fn visit_use(&mut self, path: &'tcx UsePath<'tcx>, hir_id: HirId) {
let res = path.res;
// A use item can import something from two namespaces at the same time.
// For deprecation/stability we don't want to warn twice.
// This specifically happens with constructors for unit/tuple structs.
if let Some(ty_ns_res) = res.type_ns
&& let Some(value_ns_res) = res.value_ns
&& let Some(type_ns_did) = ty_ns_res.opt_def_id()
&& let Some(value_ns_did) = value_ns_res.opt_def_id()
&& let DefKind::Ctor(.., _) = self.tcx.def_kind(value_ns_did)
&& self.tcx.parent(value_ns_did) == type_ns_did
{
// Only visit the value namespace path when we've detected a duplicate,
// not the type namespace path.
let UsePath { segments, res: _, span } = *path;
self.visit_path(&Path { segments, res: value_ns_res, span }, hir_id);
// Though, visit the macro namespace if it exists,
// regardless of the checks above relating to constructors.
if let Some(res) = res.macro_ns {
self.visit_path(&Path { segments, res, span }, hir_id);
}
} else {
// if there's no duplicate, just walk as normal
intravisit::walk_use(self, path, hir_id)
}
}
fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
if let Some(def_id) = path.res.opt_def_id() {
let method_span = path.segments.last().map(|s| s.ident.span);

View file

@ -0,0 +1,45 @@
#![deny(deprecated)]
#[deprecated]
pub mod a {
pub struct Foo;
pub struct Bar();
pub struct Baz {}
pub enum Enum {
VFoo,
VBar(),
VBaz {},
}
}
use a::Foo;
//~^ ERROR use of deprecated unit struct `a::Foo`
use a::Bar;
//~^ ERROR use of deprecated tuple struct `a::Bar`
use a::Baz;
//~^ ERROR use of deprecated struct `a::Baz`
use a::Enum::VFoo;
//~^ ERROR use of deprecated unit variant `a::Enum::VFoo`
use a::Enum::VBar;
//~^ ERROR use of deprecated tuple variant `a::Enum::VBar`
use a::Enum::VBaz;
//~^ ERROR use of deprecated variant `a::Enum::VBaz`
fn main() {
a::Foo;
//~^ ERROR use of deprecated unit struct `a::Foo`
a::Bar();
//~^ ERROR use of deprecated tuple struct `a::Bar`
a::Baz {};
//~^ ERROR use of deprecated struct `a::Baz`
a::Enum::VFoo;
//~^ ERROR use of deprecated unit variant `a::Enum::VFoo`
a::Enum::VBar();
//~^ ERROR use of deprecated tuple variant `a::Enum::VBar`
a::Enum::VBaz{};
//~^ ERROR use of deprecated variant `a::Enum::VBaz`
}

View file

@ -0,0 +1,80 @@
error: use of deprecated unit struct `a::Foo`
--> $DIR/unit_and_tuple_struct.rs:17:8
|
LL | use a::Foo;
| ^^^
|
note: the lint level is defined here
--> $DIR/unit_and_tuple_struct.rs:1:9
|
LL | #![deny(deprecated)]
| ^^^^^^^^^^
error: use of deprecated tuple struct `a::Bar`
--> $DIR/unit_and_tuple_struct.rs:19:8
|
LL | use a::Bar;
| ^^^
error: use of deprecated struct `a::Baz`
--> $DIR/unit_and_tuple_struct.rs:21:8
|
LL | use a::Baz;
| ^^^
error: use of deprecated unit variant `a::Enum::VFoo`
--> $DIR/unit_and_tuple_struct.rs:24:14
|
LL | use a::Enum::VFoo;
| ^^^^
error: use of deprecated tuple variant `a::Enum::VBar`
--> $DIR/unit_and_tuple_struct.rs:26:14
|
LL | use a::Enum::VBar;
| ^^^^
error: use of deprecated variant `a::Enum::VBaz`
--> $DIR/unit_and_tuple_struct.rs:28:14
|
LL | use a::Enum::VBaz;
| ^^^^
error: use of deprecated unit struct `a::Foo`
--> $DIR/unit_and_tuple_struct.rs:32:6
|
LL | a::Foo;
| ^^^
error: use of deprecated tuple struct `a::Bar`
--> $DIR/unit_and_tuple_struct.rs:34:6
|
LL | a::Bar();
| ^^^
error: use of deprecated struct `a::Baz`
--> $DIR/unit_and_tuple_struct.rs:36:6
|
LL | a::Baz {};
| ^^^
error: use of deprecated unit variant `a::Enum::VFoo`
--> $DIR/unit_and_tuple_struct.rs:39:12
|
LL | a::Enum::VFoo;
| ^^^^
error: use of deprecated tuple variant `a::Enum::VBar`
--> $DIR/unit_and_tuple_struct.rs:41:12
|
LL | a::Enum::VBar();
| ^^^^
error: use of deprecated variant `a::Enum::VBaz`
--> $DIR/unit_and_tuple_struct.rs:43:12
|
LL | a::Enum::VBaz{};
| ^^^^
error: aborting due to 12 previous errors