diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 2ee1bd0dfd1e..af78954ba154 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -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); diff --git a/tests/ui/deprecation/unit_and_tuple_struct.rs b/tests/ui/deprecation/unit_and_tuple_struct.rs index c1f757d9547d..5f1484e7431d 100644 --- a/tests/ui/deprecation/unit_and_tuple_struct.rs +++ b/tests/ui/deprecation/unit_and_tuple_struct.rs @@ -1,5 +1,4 @@ #![deny(deprecated)] -#![allow(unused_imports)] #[deprecated] pub mod a { @@ -16,20 +15,16 @@ pub mod a { use a::Foo; -//~^ ERROR use of deprecated struct `a::Foo` -//~| ERROR use of deprecated unit struct `a::Foo` +//~^ ERROR use of deprecated unit struct `a::Foo` use a::Bar; -//~^ ERROR use of deprecated struct `a::Bar` -//~| ERROR use of deprecated tuple struct `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 variant `a::Enum::VFoo` -//~| ERROR use of deprecated unit variant `a::Enum::VFoo` +//~^ ERROR use of deprecated unit variant `a::Enum::VFoo` use a::Enum::VBar; -//~^ ERROR use of deprecated variant `a::Enum::VBar` -//~| ERROR use of deprecated tuple variant `a::Enum::VBar` +//~^ ERROR use of deprecated tuple variant `a::Enum::VBar` use a::Enum::VBaz; //~^ ERROR use of deprecated variant `a::Enum::VBaz` diff --git a/tests/ui/deprecation/unit_and_tuple_struct.stderr b/tests/ui/deprecation/unit_and_tuple_struct.stderr index 5d1c4dcb23c3..4408eaefb81e 100644 --- a/tests/ui/deprecation/unit_and_tuple_struct.stderr +++ b/tests/ui/deprecation/unit_and_tuple_struct.stderr @@ -1,5 +1,5 @@ -error: use of deprecated struct `a::Foo` - --> $DIR/unit_and_tuple_struct.rs:18:8 +error: use of deprecated unit struct `a::Foo` + --> $DIR/unit_and_tuple_struct.rs:17:8 | LL | use a::Foo; | ^^^ @@ -10,95 +10,71 @@ note: the lint level is defined here LL | #![deny(deprecated)] | ^^^^^^^^^^ -error: use of deprecated unit struct `a::Foo` - --> $DIR/unit_and_tuple_struct.rs:18:8 - | -LL | use a::Foo; - | ^^^ - -error: use of deprecated struct `a::Bar` - --> $DIR/unit_and_tuple_struct.rs:21:8 - | -LL | use a::Bar; - | ^^^ - error: use of deprecated tuple struct `a::Bar` - --> $DIR/unit_and_tuple_struct.rs:21:8 + --> $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:24:8 + --> $DIR/unit_and_tuple_struct.rs:21:8 | LL | use a::Baz; | ^^^ -error: use of deprecated variant `a::Enum::VFoo` - --> $DIR/unit_and_tuple_struct.rs:27:14 - | -LL | use a::Enum::VFoo; - | ^^^^ - error: use of deprecated unit variant `a::Enum::VFoo` - --> $DIR/unit_and_tuple_struct.rs:27:14 + --> $DIR/unit_and_tuple_struct.rs:24:14 | LL | use a::Enum::VFoo; | ^^^^ -error: use of deprecated variant `a::Enum::VBar` - --> $DIR/unit_and_tuple_struct.rs:30:14 - | -LL | use a::Enum::VBar; - | ^^^^ - error: use of deprecated tuple variant `a::Enum::VBar` - --> $DIR/unit_and_tuple_struct.rs:30:14 + --> $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:33:14 + --> $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:37:6 + --> $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:39:6 + --> $DIR/unit_and_tuple_struct.rs:34:6 | LL | a::Bar(); | ^^^ error: use of deprecated struct `a::Baz` - --> $DIR/unit_and_tuple_struct.rs:41:6 + --> $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:44:12 + --> $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:46:12 + --> $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:48:12 + --> $DIR/unit_and_tuple_struct.rs:43:12 | LL | a::Enum::VBaz{}; | ^^^^ -error: aborting due to 16 previous errors +error: aborting due to 12 previous errors