Skip to content

Commit f552299

Browse files
committed
typeck: always lint for user's shadows
`collision_safe` works when the new-unstable item is only shadowing a from-std stable item, but it could also shadow a user-defined item from a extension trait, in which case the lint should still fire. Use the presence of a stability attribute on a chosen item as a heuristic for a std item and continue to lint if the chosen item isn't from std even if the unstable items are collision-safe. Signed-off-by: David Wood <[email protected]>
1 parent 8644b90 commit f552299

File tree

4 files changed

+120
-15
lines changed

4 files changed

+120
-15
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

+24-15
Original file line numberDiff line numberDiff line change
@@ -1367,21 +1367,30 @@ impl<'tcx> Pick<'tcx> {
13671367
span: Span,
13681368
scope_expr_id: hir::HirId,
13691369
) {
1370-
if self.unstable_candidates.is_empty() {
1371-
return;
1372-
}
1373-
1374-
if self.unstable_candidates.iter().all(|(candidate, _)| {
1375-
let stab = tcx.lookup_stability(candidate.item.def_id);
1376-
debug!(?candidate, ?stab);
1377-
matches!(
1378-
stab,
1379-
Some(Stability {
1380-
level: StabilityLevel::Unstable { collision_safe: true, .. },
1381-
..
1382-
})
1383-
)
1384-
}) {
1370+
if self.unstable_candidates.is_empty()
1371+
|| !{
1372+
let has_collision_unsafe_candidate =
1373+
self.unstable_candidates.iter().any(|(candidate, _)| {
1374+
let stab = tcx.lookup_stability(candidate.item.def_id);
1375+
!matches!(
1376+
stab,
1377+
Some(Stability {
1378+
level: StabilityLevel::Unstable { collision_safe: true, .. },
1379+
..
1380+
})
1381+
)
1382+
});
1383+
// `collision_safe` shouldn't silence the lint when the selected candidate is from
1384+
// user code, only when it is a collision with an item from std (where the
1385+
// assumption is that t-libs have confirmed that such a collision is okay). Use the
1386+
// existence of a stability attribute on the selected candidate has a heuristic
1387+
// for item from std.
1388+
let chosen_candidate_has_stability =
1389+
tcx.lookup_stability(self.item.def_id).is_some();
1390+
debug!(?has_collision_unsafe_candidate, ?chosen_candidate_has_stability, ?self);
1391+
has_collision_unsafe_candidate || !chosen_candidate_has_stability
1392+
}
1393+
{
13851394
return;
13861395
}
13871396

src/test/ui/stability-attribute/auxiliary/stability-attribute-collision-safe.rs

+32
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,35 @@ impl Bar {
4040
2
4141
}
4242
}
43+
44+
#[stable(feature = "trait_feature", since = "1.0.0")]
45+
pub trait Trait {
46+
#[unstable(feature = "new_trait_feature", issue = "none")]
47+
fn not_safe(&self) -> u32 {
48+
0
49+
}
50+
51+
#[unstable(feature = "new_trait_feature", issue = "none", collision_safe)]
52+
fn safe(&self) -> u32 {
53+
0
54+
}
55+
56+
#[unstable(feature = "new_trait_feature", issue = "none", collision_safe)]
57+
fn safe_and_shadowing_a_stable_item(&self) -> u32 {
58+
0
59+
}
60+
}
61+
62+
#[stable(feature = "trait_feature", since = "1.0.0")]
63+
pub trait OtherTrait {
64+
#[stable(feature = "trait_feature", since = "1.0.0")]
65+
fn safe_and_shadowing_a_stable_item(&self) -> u32 {
66+
4
67+
}
68+
}
69+
70+
#[stable(feature = "trait_feature", since = "1.0.0")]
71+
impl Trait for char { }
72+
73+
#[stable(feature = "trait_feature", since = "1.0.0")]
74+
impl OtherTrait for char { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// aux-build:stability-attribute-collision-safe.rs
2+
#![deny(unstable_name_collisions)]
3+
4+
extern crate stability_attribute_collision_safe;
5+
use stability_attribute_collision_safe::{Trait, OtherTrait};
6+
7+
pub trait LocalTrait {
8+
fn not_safe(&self) -> u32 {
9+
1
10+
}
11+
12+
fn safe(&self) -> u32 {
13+
1
14+
}
15+
}
16+
17+
impl LocalTrait for char {}
18+
19+
20+
fn main() {
21+
// Despite having `collision_safe` on defn, the fn chosen doesn't have a stability attribute,
22+
// thus could be user code (and is in this test), so the lint is still appropriate..
23+
assert_eq!('x'.safe(), 1);
24+
//~^ ERROR an associated function with this name may be added to the standard library in the future
25+
//~^^ WARN once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
26+
27+
// ..but with `collision_safe` on defn, if the chosen item has a stability attribute, then
28+
// assumed to be from std or somewhere that's been checked to be okay, so no lint..
29+
assert_eq!('x'.safe_and_shadowing_a_stable_item(), 4); // okay!
30+
31+
// ..and not safe functions should, of course, still lint..
32+
assert_eq!('x'.not_safe(), 1);
33+
//~^ ERROR an associated function with this name may be added to the standard library in the future
34+
//~^^ WARN once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: an associated function with this name may be added to the standard library in the future
2+
--> $DIR/stability-attribute-collision-safe-user.rs:23:20
3+
|
4+
LL | assert_eq!('x'.safe(), 1);
5+
| ^^^^
6+
|
7+
= warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
8+
= note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
9+
= help: call with fully qualified syntax `LocalTrait::safe(...)` to keep using the current method
10+
= help: add `#![feature(new_trait_feature)]` to the crate attributes to enable `safe`
11+
note: the lint level is defined here
12+
--> $DIR/stability-attribute-collision-safe-user.rs:2:9
13+
|
14+
LL | #![deny(unstable_name_collisions)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error: an associated function with this name may be added to the standard library in the future
18+
--> $DIR/stability-attribute-collision-safe-user.rs:32:20
19+
|
20+
LL | assert_eq!('x'.not_safe(), 1);
21+
| ^^^^^^^^
22+
|
23+
= warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
24+
= note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
25+
= help: call with fully qualified syntax `LocalTrait::not_safe(...)` to keep using the current method
26+
= help: add `#![feature(new_trait_feature)]` to the crate attributes to enable `not_safe`
27+
28+
error: aborting due to 2 previous errors
29+

0 commit comments

Comments
 (0)