Skip to content
/ rust Public
forked from rust-lang/rust

Commit e4c98ca

Browse files
committed
Auto merge of rust-lang#113312 - Ddystopia:auto-trait-fun, r=lcnr
discard default auto trait impls if explicit ones exist (rebase of rust-lang#85048) Rebase of rust-lang#85048
2 parents aafd75a + 3715934 commit e4c98ca

File tree

8 files changed

+146
-20
lines changed

8 files changed

+146
-20
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4052,12 +4052,12 @@ declare_lint! {
40524052
///
40534053
/// The compiler disables the automatic implementation if an explicit one
40544054
/// exists for given type constructor. The exact rules governing this
4055-
/// are currently unsound, quite subtle, and will be modified in the future.
4056-
/// This change will cause the automatic implementation to be disabled in more
4055+
/// were previously unsound, quite subtle, and have been recently modified.
4056+
/// This change caused the automatic implementation to be disabled in more
40574057
/// cases, potentially breaking some code.
40584058
pub SUSPICIOUS_AUTO_TRAIT_IMPLS,
40594059
Warn,
4060-
"the rules governing auto traits will change in the future",
4060+
"the rules governing auto traits have recently changed resulting in potential breakage",
40614061
@future_incompatible = FutureIncompatibleInfo {
40624062
reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
40634063
reference: "issue #93367 <https://github.com/rust-lang/rust/issues/93367>",

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+59-7
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
124124

125125
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
126126
self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
127-
// Auto implementations have lower priority, so we only
128-
// consider triggering a default if there is no other impl that can apply.
129-
if candidates.vec.is_empty() {
130-
self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
131-
}
127+
self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
132128
}
133129
debug!("candidate list size: {}", candidates.vec.len());
134130
Ok(candidates)
@@ -513,7 +509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
513509
// for an example of a test case that exercises
514510
// this path.
515511
}
516-
ty::Infer(ty::TyVar(_)) => {
512+
ty::Infer(ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_)) => {
517513
// The auto impl might apply; we don't know.
518514
candidates.ambiguous = true;
519515
}
@@ -533,7 +529,63 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
533529
}
534530
}
535531

536-
_ => candidates.vec.push(AutoImplCandidate),
532+
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
533+
bug!(
534+
"asked to assemble auto trait candidates of unexpected type: {:?}",
535+
self_ty
536+
);
537+
}
538+
539+
ty::Alias(_, _)
540+
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) =>
541+
{
542+
// We do not generate an auto impl candidate for `impl Trait`s which already
543+
// reference our auto trait.
544+
//
545+
// For example during candidate assembly for `impl Send: Send`, we don't have
546+
// to look at the constituent types for this opaque types to figure out that this
547+
// trivially holds.
548+
//
549+
// Note that this is only sound as projection candidates of opaque types
550+
// are always applicable for auto traits.
551+
}
552+
ty::Alias(_, _) => candidates.vec.push(AutoImplCandidate),
553+
554+
ty::Bool
555+
| ty::Char
556+
| ty::Int(_)
557+
| ty::Uint(_)
558+
| ty::Float(_)
559+
| ty::Str
560+
| ty::Array(_, _)
561+
| ty::Slice(_)
562+
| ty::Adt(..)
563+
| ty::RawPtr(_)
564+
| ty::Ref(..)
565+
| ty::FnDef(..)
566+
| ty::FnPtr(_)
567+
| ty::Closure(_, _)
568+
| ty::Generator(..)
569+
| ty::Never
570+
| ty::Tuple(_)
571+
| ty::GeneratorWitness(_)
572+
| ty::GeneratorWitnessMIR(..) => {
573+
// Only consider auto impls if there are no manual impls for the root of `self_ty`.
574+
//
575+
// For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
576+
// for `&SomeType: Auto` exists. Due to E0321 the only crate where impls
577+
// for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined.
578+
//
579+
// Generally, we have to guarantee that for all `SimplifiedType`s the only crate
580+
// which may define impls for that type is either the crate defining the type
581+
// or the trait. This should be guaranteed by the orphan check.
582+
let mut has_impl = false;
583+
self.tcx().for_each_relevant_impl(def_id, self_ty, |_| has_impl = true);
584+
if !has_impl {
585+
candidates.vec.push(AutoImplCandidate)
586+
}
587+
}
588+
ty::Error(_) => {} // do not add an auto trait impl for `ty::Error` for now.
537589
}
538590
}
539591
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
17831783
/// candidates and prefer where-clause candidates.
17841784
///
17851785
/// See the comment for "SelectionCandidate" for more details.
1786+
#[instrument(level = "debug", skip(self))]
17861787
fn candidate_should_be_dropped_in_favor_of(
17871788
&mut self,
17881789
victim: &EvaluatedCandidate<'tcx>,
@@ -1806,13 +1807,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18061807
// This is a fix for #53123 and prevents winnowing from accidentally extending the
18071808
// lifetime of a variable.
18081809
match (&other.candidate, &victim.candidate) {
1809-
(_, AutoImplCandidate) | (AutoImplCandidate, _) => {
1810-
bug!(
1811-
"default implementations shouldn't be recorded \
1812-
when there are other valid candidates"
1813-
);
1814-
}
1815-
18161810
// FIXME(@jswrenn): this should probably be more sophisticated
18171811
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No,
18181812

@@ -1854,6 +1848,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18541848
(
18551849
ParamCandidate(ref other_cand),
18561850
ImplCandidate(..)
1851+
| AutoImplCandidate
18571852
| ClosureCandidate { .. }
18581853
| GeneratorCandidate
18591854
| FutureCandidate
@@ -1881,6 +1876,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18811876
}
18821877
(
18831878
ImplCandidate(_)
1879+
| AutoImplCandidate
18841880
| ClosureCandidate { .. }
18851881
| GeneratorCandidate
18861882
| FutureCandidate
@@ -1914,6 +1910,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19141910
(
19151911
ObjectCandidate(_) | ProjectionCandidate(..),
19161912
ImplCandidate(..)
1913+
| AutoImplCandidate
19171914
| ClosureCandidate { .. }
19181915
| GeneratorCandidate
19191916
| FutureCandidate
@@ -1927,6 +1924,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19271924

19281925
(
19291926
ImplCandidate(..)
1927+
| AutoImplCandidate
19301928
| ClosureCandidate { .. }
19311929
| GeneratorCandidate
19321930
| FutureCandidate
@@ -2017,6 +2015,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
20172015
}
20182016
}
20192017

2018+
(AutoImplCandidate, ImplCandidate(_)) | (ImplCandidate(_), AutoImplCandidate) => {
2019+
DropVictim::No
2020+
}
2021+
2022+
(AutoImplCandidate, _) | (_, AutoImplCandidate) => {
2023+
bug!(
2024+
"default implementations shouldn't be recorded \
2025+
when there are other global candidates: {:?} {:?}",
2026+
other,
2027+
victim
2028+
);
2029+
}
2030+
20202031
// Everything else is ambiguous
20212032
(
20222033
ImplCandidate(_)
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![allow(suspicious_auto_trait_impls)]
2+
3+
struct Always<T, U>(T, U);
4+
unsafe impl<T, U> Send for Always<T, U> {}
5+
struct Foo<T, U>(Always<T, U>);
6+
7+
trait False {}
8+
unsafe impl<U: False> Send for Foo<u32, U> {}
9+
10+
trait WithAssoc {
11+
type Output;
12+
}
13+
impl<T: Send> WithAssoc for T {
14+
type Output = Self;
15+
}
16+
impl WithAssoc for Foo<u32, ()> {
17+
type Output = Box<i32>;
18+
}
19+
20+
fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) {
21+
//~^ ERROR `Foo<T, U>` cannot be sent between threads safely
22+
f(foo(v));
23+
}
24+
25+
fn foo<T: Send>(x: T) -> <T as WithAssoc>::Output {
26+
x
27+
}
28+
29+
fn main() {
30+
generic(Foo(Always(0, ())), |b| *b);
31+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0277]: `Foo<T, U>` cannot be sent between threads safely
2+
--> $DIR/issue-83857-ub.rs:20:38
3+
|
4+
LL | fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo<T, U>` cannot be sent between threads safely
6+
|
7+
= help: the trait `Send` is not implemented for `Foo<T, U>`
8+
note: required for `Foo<T, U>` to implement `WithAssoc`
9+
--> $DIR/issue-83857-ub.rs:13:15
10+
|
11+
LL | impl<T: Send> WithAssoc for T {
12+
| ---- ^^^^^^^^^ ^
13+
| |
14+
| unsatisfied trait bound introduced here
15+
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
16+
|
17+
LL | fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) where Foo<T, U>: Send {
18+
| +++++++++++++++++++++
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0277`.

tests/ui/generator/auto-trait-regions.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn assert_foo<T: Foo>(f: T) {}
2626
fn main() {
2727
// Make sure 'static is erased for generator interiors so we can't match it in trait selection
2828
let x: &'static _ = &OnlyFooIfStaticRef(No);
29-
let gen = || {
29+
let gen = move || {
3030
let x = x;
3131
yield;
3232
assert_foo(x);
@@ -36,15 +36,15 @@ fn main() {
3636

3737
// Allow impls which matches any lifetime
3838
let x = &OnlyFooIfRef(No);
39-
let gen = || {
39+
let gen = move || {
4040
let x = x;
4141
yield;
4242
assert_foo(x);
4343
};
4444
assert_foo(gen); // ok
4545

4646
// Disallow impls which relates lifetimes in the generator interior
47-
let gen = || {
47+
let gen = move || {
4848
let a = A(&mut true, &mut true, No);
4949
//~^ temporary value dropped while borrowed
5050
//~| temporary value dropped while borrowed

tests/ui/impl-trait/auto-trait-leak

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// check-pass
2+
fn is_send<T: Send>(_: T) {}
3+
fn foo() -> impl Send {
4+
if false {
5+
is_send(foo());
6+
}
7+
()
8+
}
9+
10+
fn main() {}

0 commit comments

Comments
 (0)