Skip to content

Commit 363faba

Browse files
committed
lint impls that will become incoherent when leak-check is removed
1 parent e9c7894 commit 363faba

13 files changed

+166
-17
lines changed

Diff for: src/librustc/infer/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -836,14 +836,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
836836
r
837837
}
838838

839-
/// Execute `f` then unroll any bindings it creates.
840-
pub fn skip_leak_check<R, F>(&self, f: F) -> R
839+
/// If `should_skip` is true, then execute `f` then unroll any bindings it creates.
840+
pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
841841
where
842842
F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
843843
{
844844
debug!("probe()");
845845
let snapshot = self.start_snapshot();
846-
self.skip_leak_check.set(true);
846+
let skip_leak_check = should_skip || self.skip_leak_check.get();
847+
self.skip_leak_check.set(skip_leak_check);
847848
let r = f(&snapshot);
848849
self.rollback_to("probe", snapshot);
849850
r

Diff for: src/librustc/traits/coherence.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use crate::infer::{CombinedSnapshot, InferOk};
88
use crate::traits::select::IntercrateAmbiguityCause;
99
use crate::traits::IntercrateMode;
10+
use crate::traits::SkipLeakCheck;
1011
use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
1112
use crate::ty::fold::TypeFoldable;
1213
use crate::ty::subst::Subst;
@@ -53,6 +54,7 @@ pub fn overlapping_impls<F1, F2, R>(
5354
impl1_def_id: DefId,
5455
impl2_def_id: DefId,
5556
intercrate_mode: IntercrateMode,
57+
skip_leak_check: SkipLeakCheck,
5658
on_overlap: F1,
5759
no_overlap: F2,
5860
) -> R
@@ -70,7 +72,7 @@ where
7072

7173
let overlaps = tcx.infer_ctxt().enter(|infcx| {
7274
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
73-
overlap(selcx, impl1_def_id, impl2_def_id).is_some()
75+
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some()
7476
});
7577

7678
if !overlaps {
@@ -83,7 +85,7 @@ where
8385
tcx.infer_ctxt().enter(|infcx| {
8486
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
8587
selcx.enable_tracking_intercrate_ambiguity_causes();
86-
on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
88+
on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap())
8789
})
8890
}
8991

@@ -113,12 +115,15 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
113115
/// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls.
114116
fn overlap<'cx, 'tcx>(
115117
selcx: &mut SelectionContext<'cx, 'tcx>,
118+
skip_leak_check: SkipLeakCheck,
116119
a_def_id: DefId,
117120
b_def_id: DefId,
118121
) -> Option<OverlapResult<'tcx>> {
119122
debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
120123

121-
selcx.infcx().probe(|snapshot| overlap_within_probe(selcx, a_def_id, b_def_id, snapshot))
124+
selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
125+
overlap_within_probe(selcx, a_def_id, b_def_id, snapshot)
126+
})
122127
}
123128

124129
fn overlap_within_probe(
@@ -146,7 +151,9 @@ fn overlap_within_probe(
146151
.eq_impl_headers(&a_impl_header, &b_impl_header)
147152
{
148153
Ok(InferOk { obligations, value: () }) => obligations,
149-
Err(_) => return None,
154+
Err(_) => {
155+
return None;
156+
}
150157
};
151158

152159
debug!("overlap: unification check succeeded");

Diff for: src/librustc/traits/mod.rs

+22
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,28 @@ pub enum IntercrateMode {
8383
Fixed,
8484
}
8585

86+
/// Whether to skip the leak check, as part of a future compatibility warning step.
87+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
88+
pub enum SkipLeakCheck {
89+
Yes,
90+
No,
91+
}
92+
93+
impl SkipLeakCheck {
94+
fn is_yes(self) -> bool {
95+
self == SkipLeakCheck::Yes
96+
}
97+
}
98+
99+
/// The "default" for skip-leak-check corresponds to the current
100+
/// behavior (do not skip the leak check) -- not the behavior we are
101+
/// transitioning into.
102+
impl Default for SkipLeakCheck {
103+
fn default() -> Self {
104+
SkipLeakCheck::No
105+
}
106+
}
107+
86108
/// The mode that trait queries run in.
87109
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
88110
pub enum TraitQueryMode {

Diff for: src/librustc/traits/specialize/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::ty::{self, TyCtxt, TypeFoldable};
1919
use rustc_data_structures::fx::FxHashSet;
2020
use rustc_errors::struct_span_err;
2121
use rustc_hir::def_id::DefId;
22+
use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
2223
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
2324
use rustc_span::DUMMY_SP;
2425

@@ -97,7 +98,7 @@ pub fn translate_substs<'a, 'tcx>(
9798
|_| {
9899
bug!(
99100
"When translating substitutions for specialization, the expected \
100-
specialization failed to hold"
101+
specialization failed to hold"
101102
)
102103
},
103104
)
@@ -268,7 +269,7 @@ fn fulfill_implication<'a, 'tcx>(
268269
// no dice!
269270
debug!(
270271
"fulfill_implication: for impls on {:?} and {:?}, \
271-
could not fulfill: {:?} given {:?}",
272+
could not fulfill: {:?} given {:?}",
272273
source_trait_ref, target_trait_ref, errors, param_env.caller_bounds
273274
);
274275
Err(())
@@ -342,6 +343,7 @@ pub(super) fn specialization_graph_provider(
342343
FutureCompatOverlapErrorKind::Issue33140 => {
343344
ORDER_DEPENDENT_TRAIT_OBJECTS
344345
}
346+
FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
345347
};
346348
tcx.struct_span_lint_hir(
347349
lint,

Diff for: src/librustc/traits/specialize/specialization_graph.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub use rustc::traits::types::specialization_graph::*;
1111
pub enum FutureCompatOverlapErrorKind {
1212
Issue43355,
1313
Issue33140,
14+
LeakCheck,
1415
}
1516

1617
#[derive(Debug)]
@@ -111,6 +112,7 @@ impl<'tcx> Children {
111112
possible_sibling,
112113
impl_def_id,
113114
traits::IntercrateMode::Issue43355,
115+
traits::SkipLeakCheck::default(),
114116
|overlap| {
115117
if let Some(overlap_kind) =
116118
tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
@@ -161,6 +163,7 @@ impl<'tcx> Children {
161163
possible_sibling,
162164
impl_def_id,
163165
traits::IntercrateMode::Fixed,
166+
traits::SkipLeakCheck::default(),
164167
|overlap| {
165168
last_lint = Some(FutureCompatOverlapError {
166169
error: overlap_error(overlap),
@@ -169,6 +172,23 @@ impl<'tcx> Children {
169172
},
170173
|| (),
171174
);
175+
176+
if last_lint.is_none() {
177+
traits::overlapping_impls(
178+
tcx,
179+
possible_sibling,
180+
impl_def_id,
181+
traits::IntercrateMode::Fixed,
182+
traits::SkipLeakCheck::Yes,
183+
|overlap| {
184+
last_lint = Some(FutureCompatOverlapError {
185+
error: overlap_error(overlap),
186+
kind: FutureCompatOverlapErrorKind::LeakCheck,
187+
});
188+
},
189+
|| (),
190+
);
191+
}
172192
}
173193

174194
// no overlap (error bailed already via ?)
@@ -247,7 +267,7 @@ impl<'tcx> Graph {
247267
if trait_ref.references_error() {
248268
debug!(
249269
"insert: inserting dummy node for erroneous TraitRef {:?}, \
250-
impl_def_id={:?}, trait_def_id={:?}",
270+
impl_def_id={:?}, trait_def_id={:?}",
251271
trait_ref, impl_def_id, trait_def_id
252272
);
253273

@@ -326,7 +346,7 @@ impl<'tcx> Graph {
326346
if self.parent.insert(child, parent).is_some() {
327347
bug!(
328348
"When recording an impl from the crate store, information about its parent \
329-
was already present."
349+
was already present."
330350
);
331351
}
332352

Diff for: src/librustc_session/lint/builtin.rs

+11
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,16 @@ declare_lint! {
260260
};
261261
}
262262

263+
declare_lint! {
264+
pub COHERENCE_LEAK_CHECK,
265+
Deny,
266+
"distinct impls distinguished only by the leak-check code",
267+
@future_incompatible = FutureIncompatibleInfo {
268+
reference: "issue #56105 <https://github.com/rust-lang/rust/issues/56105>",
269+
edition: None,
270+
};
271+
}
272+
263273
declare_lint! {
264274
pub DEPRECATED,
265275
Warn,
@@ -509,6 +519,7 @@ declare_lint_pass! {
509519
MISSING_FRAGMENT_SPECIFIER,
510520
LATE_BOUND_LIFETIME_ARGUMENTS,
511521
ORDER_DEPENDENT_TRAIT_OBJECTS,
522+
COHERENCE_LEAK_CHECK,
512523
DEPRECATED,
513524
UNUSED_UNSAFE,
514525
UNUSED_MUT,

Diff for: src/librustc_typeck/coherence/inherent_impls_overlap.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::namespace::Namespace;
2-
use rustc::traits::{self, IntercrateMode};
2+
use rustc::traits::{self, IntercrateMode, SkipLeakCheck};
33
use rustc::ty::TyCtxt;
44
use rustc_errors::struct_span_err;
55
use rustc_hir as hir;
@@ -76,6 +76,9 @@ impl InherentOverlapChecker<'tcx> {
7676
impl1_def_id,
7777
impl2_def_id,
7878
IntercrateMode::Issue43355,
79+
// We go ahead and just skip the leak check for
80+
// inherent impls without warning.
81+
SkipLeakCheck::Yes,
7982
|overlap| {
8083
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
8184
false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0592]: duplicate definitions with name `method1`
2+
--> $DIR/coherence-inherited-subtyping.rs:14:5
3+
|
4+
LL | fn method1(&self) {}
5+
| ^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `method1`
6+
...
7+
LL | fn method1(&self) {}
8+
| -------------------- other definition for `method1`
9+
|
10+
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0592`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0592]: duplicate definitions with name `method1`
2+
--> $DIR/coherence-inherited-subtyping.rs:14:5
3+
|
4+
LL | fn method1(&self) {}
5+
| ^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `method1`
6+
...
7+
LL | fn method1(&self) {}
8+
| -------------------- other definition for `method1`
9+
|
10+
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0592`.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Test that two distinct impls which match subtypes of one another
2+
// yield coherence errors (or not) depending on the variance.
3+
//
4+
// Note: This scenario is currently accepted, but as part of the
5+
// universe transition (#56105) may eventually become an error.
6+
7+
// revisions: old re
8+
9+
struct Foo<T> {
10+
t: T,
11+
}
12+
13+
impl Foo<for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8> {
14+
fn method1(&self) {} //~ ERROR duplicate definitions with name `method1`
15+
}
16+
17+
impl Foo<for<'a> fn(&'a u8, &'a u8) -> &'a u8> {
18+
fn method1(&self) {}
19+
}
20+
21+
fn main() {}

Diff for: src/test/ui/coherence/coherence-subtyping.old.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
2+
--> $DIR/coherence-subtyping.rs:15:1
3+
|
4+
LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
5+
| ---------------------------------------------------------- first implementation here
6+
LL |
7+
LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
9+
|
10+
= note: `#[deny(coherence_leak_check)]` on by default
11+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
12+
= note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
13+
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
14+
15+
error: aborting due to previous error
16+

Diff for: src/test/ui/coherence/coherence-subtyping.re.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
2+
--> $DIR/coherence-subtyping.rs:15:1
3+
|
4+
LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
5+
| ---------------------------------------------------------- first implementation here
6+
LL |
7+
LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
9+
|
10+
= note: `#[deny(coherence_leak_check)]` on by default
11+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
12+
= note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
13+
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
14+
15+
error: aborting due to previous error
16+

Diff for: src/test/ui/coherence/coherence-subtyping.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55
// universe transition (#56105) may eventually become an error.
66

77
// revisions: old re
8-
// build-pass (FIXME(62277): could be check-pass?)
98

109
trait TheTrait {
11-
fn foo(&self) { }
10+
fn foo(&self) {}
1211
}
1312

14-
impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
15-
}
13+
impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
1614

1715
impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
16+
//[re]~^ ERROR conflicting implementation
17+
//[re]~^^ WARNING this was previously accepted by the compiler but is being phased out
18+
//[old]~^^^ ERROR conflicting implementation
19+
//[old]~^^^^ WARNING this was previously accepted by the compiler but is being phased out
1820
}
1921

20-
fn main() { }
22+
fn main() {}

0 commit comments

Comments
 (0)