Skip to content

Commit 4c08ed5

Browse files
committed
convert the new conflicts to a soft error
1 parent 5360699 commit 4c08ed5

File tree

10 files changed

+207
-64
lines changed

10 files changed

+207
-64
lines changed

src/librustc/lint/builtin.rs

+7
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ declare_lint! {
198198
"detects generic lifetime arguments in path segments with late bound lifetime parameters"
199199
}
200200

201+
declare_lint! {
202+
pub INCOHERENT_FUNDAMENTAL_IMPLS,
203+
Deny,
204+
"potentially-conflicting impls were erroneously allowed"
205+
}
206+
201207
declare_lint! {
202208
pub DEPRECATED,
203209
Warn,
@@ -254,6 +260,7 @@ impl LintPass for HardwiredLints {
254260
MISSING_FRAGMENT_SPECIFIER,
255261
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
256262
LATE_BOUND_LIFETIME_ARGUMENTS,
263+
INCOHERENT_FUNDAMENTAL_IMPLS,
257264
DEPRECATED,
258265
UNUSED_UNSAFE,
259266
UNUSED_MUT

src/librustc/traits/coherence.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use hir::def_id::{DefId, LOCAL_CRATE};
1414
use syntax_pos::DUMMY_SP;
1515
use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal};
16+
use traits::IntercrateMode;
1617
use traits::select::IntercrateAmbiguityCause;
1718
use ty::{self, Ty, TyCtxt};
1819
use ty::subst::Subst;
@@ -42,16 +43,19 @@ pub struct OverlapResult<'tcx> {
4243
/// `ImplHeader` with those types substituted
4344
pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
4445
impl1_def_id: DefId,
45-
impl2_def_id: DefId)
46+
impl2_def_id: DefId,
47+
intercrate_mode: IntercrateMode)
4648
-> Option<OverlapResult<'tcx>>
4749
{
4850
debug!("impl_can_satisfy(\
4951
impl1_def_id={:?}, \
50-
impl2_def_id={:?})",
52+
impl2_def_id={:?},
53+
intercrate_mode={:?})",
5154
impl1_def_id,
52-
impl2_def_id);
55+
impl2_def_id,
56+
intercrate_mode);
5357

54-
let selcx = &mut SelectionContext::intercrate(infcx);
58+
let selcx = &mut SelectionContext::intercrate(infcx, intercrate_mode);
5559
overlap(selcx, impl1_def_id, impl2_def_id)
5660
}
5761

src/librustc/traits/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ mod structural_impls;
6060
pub mod trans;
6161
mod util;
6262

63-
#[derive(Copy, Clone, Debug)]
63+
// Whether to enable bug compatibility with issue #43355
64+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
6465
pub enum IntercrateMode {
6566
Issue43355,
6667
Fixed

src/librustc/traits/select.rs

+32-15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use self::EvaluationResult::*;
1515

1616
use super::coherence::{self, Conflict};
1717
use super::DerivedObligationCause;
18+
use super::IntercrateMode;
1819
use super::project;
1920
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
2021
use super::{PredicateObligation, TraitObligation, ObligationCause};
@@ -87,7 +88,7 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
8788
/// other words, we consider `$0 : Bar` to be unimplemented if
8889
/// there is no type that the user could *actually name* that
8990
/// would satisfy it. This avoids crippling inference, basically.
90-
intercrate: bool,
91+
intercrate: Option<IntercrateMode>,
9192

9293
inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,
9394

@@ -111,21 +112,24 @@ impl IntercrateAmbiguityCause {
111112
/// See #23980 for details.
112113
pub fn add_intercrate_ambiguity_hint<'a, 'tcx>(&self,
113114
err: &mut ::errors::DiagnosticBuilder) {
115+
err.note(&self.intercrate_ambiguity_hint());
116+
}
117+
118+
pub fn intercrate_ambiguity_hint(&self) -> String {
114119
match self {
115120
&IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => {
116121
let self_desc = if let &Some(ref ty) = self_desc {
117122
format!(" for type `{}`", ty)
118123
} else { "".to_string() };
119-
err.note(&format!("downstream crates may implement trait `{}`{}",
120-
trait_desc, self_desc));
124+
format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc)
121125
}
122126
&IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
123127
let self_desc = if let &Some(ref ty) = self_desc {
124128
format!(" for type `{}`", ty)
125129
} else { "".to_string() };
126-
err.note(&format!("upstream crates may add new impl of trait `{}`{} \
127-
in future versions",
128-
trait_desc, self_desc));
130+
format!("upstream crates may add new impl of trait `{}`{} \
131+
in future versions",
132+
trait_desc, self_desc)
129133
}
130134
}
131135
}
@@ -417,17 +421,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
417421
SelectionContext {
418422
infcx,
419423
freshener: infcx.freshener(),
420-
intercrate: false,
424+
intercrate: None,
421425
inferred_obligations: SnapshotVec::new(),
422426
intercrate_ambiguity_causes: Vec::new(),
423427
}
424428
}
425429

426-
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx, 'tcx> {
430+
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
431+
mode: IntercrateMode) -> SelectionContext<'cx, 'gcx, 'tcx> {
432+
debug!("intercrate({:?})", mode);
427433
SelectionContext {
428434
infcx,
429435
freshener: infcx.freshener(),
430-
intercrate: true,
436+
intercrate: Some(mode),
431437
inferred_obligations: SnapshotVec::new(),
432438
intercrate_ambiguity_causes: Vec::new(),
433439
}
@@ -758,7 +764,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
758764
debug!("evaluate_trait_predicate_recursively({:?})",
759765
obligation);
760766

761-
if !self.intercrate && obligation.is_global() {
767+
if !self.intercrate.is_some() && obligation.is_global() {
762768
// If a param env is consistent, global obligations do not depend on its particular
763769
// value in order to work, so we can clear out the param env and get better
764770
// caching. (If the current param env is inconsistent, we don't care what happens).
@@ -814,7 +820,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
814820
// terms of `Fn` etc, but we could probably make this more
815821
// precise still.
816822
let unbound_input_types = stack.fresh_trait_ref.input_types().any(|ty| ty.is_fresh());
817-
if unbound_input_types && self.intercrate && false {
823+
// this check was an imperfect workaround for a bug n the old
824+
// intercrate mode, it should be removed when that goes away.
825+
if unbound_input_types &&
826+
self.intercrate == Some(IntercrateMode::Issue43355)
827+
{
818828
debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
819829
stack.fresh_trait_ref);
820830
// Heuristics: show the diagnostics when there are no candidates in crate.
@@ -1212,9 +1222,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
12121222
stack: &TraitObligationStack<'o, 'tcx>)
12131223
-> Option<Conflict>
12141224
{
1215-
debug!("is_knowable(intercrate={})", self.intercrate);
1225+
debug!("is_knowable(intercrate={:?})", self.intercrate);
12161226

1217-
if !self.intercrate {
1227+
if !self.intercrate.is_some() {
12181228
return None;
12191229
}
12201230

@@ -1226,7 +1236,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
12261236
// bound regions
12271237
let trait_ref = predicate.skip_binder().trait_ref;
12281238

1229-
coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
1239+
let result = coherence::trait_ref_is_knowable(self.tcx(), trait_ref);
1240+
if let (Some(Conflict::Downstream { used_to_be_broken: true }),
1241+
Some(IntercrateMode::Issue43355)) = (result, self.intercrate) {
1242+
debug!("is_knowable: IGNORING conflict to be bug-compatible with #43355");
1243+
None
1244+
} else {
1245+
result
1246+
}
12301247
}
12311248

12321249
/// Returns true if the global caches can be used.
@@ -1251,7 +1268,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
12511268
// the master cache. Since coherence executes pretty quickly,
12521269
// it's not worth going to more trouble to increase the
12531270
// hit-rate I don't think.
1254-
if self.intercrate {
1271+
if self.intercrate.is_some() {
12551272
return false;
12561273
}
12571274

src/librustc/traits/specialize/mod.rs

+29-10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ use ty::{self, TyCtxt, TypeFoldable};
3030
use syntax_pos::DUMMY_SP;
3131
use std::rc::Rc;
3232

33+
use lint;
34+
3335
pub mod specialization_graph;
3436

3537
/// Information pertinent to an overlapping impl error.
@@ -314,16 +316,33 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
314316
// This is where impl overlap checking happens:
315317
let insert_result = sg.insert(tcx, impl_def_id);
316318
// Report error if there was one.
317-
if let Err(overlap) = insert_result {
318-
let mut err = struct_span_err!(tcx.sess,
319-
tcx.span_of_impl(impl_def_id).unwrap(),
320-
E0119,
321-
"conflicting implementations of trait `{}`{}:",
322-
overlap.trait_desc,
323-
overlap.self_desc.clone().map_or(String::new(),
324-
|ty| {
325-
format!(" for type `{}`", ty)
326-
}));
319+
let (overlap, used_to_be_allowed) = match insert_result {
320+
Err(overlap) => (Some(overlap), false),
321+
Ok(opt_overlap) => (opt_overlap, true)
322+
};
323+
324+
if let Some(overlap) = overlap {
325+
let msg = format!("conflicting implementations of trait `{}`{}:{}",
326+
overlap.trait_desc,
327+
overlap.self_desc.clone().map_or(
328+
String::new(), |ty| {
329+
format!(" for type `{}`", ty)
330+
}),
331+
if used_to_be_allowed { " (E0119)" } else { "" }
332+
);
333+
let mut err = if used_to_be_allowed {
334+
tcx.struct_span_lint_node(
335+
lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
336+
tcx.hir.as_local_node_id(impl_def_id).unwrap(),
337+
tcx.span_of_impl(impl_def_id).unwrap(),
338+
&msg)
339+
} else {
340+
struct_span_err!(tcx.sess,
341+
tcx.span_of_impl(impl_def_id).unwrap(),
342+
E0119,
343+
"{}",
344+
msg)
345+
};
327346

328347
match tcx.span_of_impl(overlap.with_impl) {
329348
Ok(span) => {

src/librustc/traits/specialize/specialization_graph.rs

+45-23
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ struct Children {
6868
/// The result of attempting to insert an impl into a group of children.
6969
enum Inserted {
7070
/// The impl was inserted as a new child in this group of children.
71-
BecameNewSibling,
71+
BecameNewSibling(Option<OverlapError>),
7272

7373
/// The impl replaced an existing impl that specializes it.
7474
Replaced(DefId),
@@ -105,17 +105,39 @@ impl<'a, 'gcx, 'tcx> Children {
105105
simplified_self: Option<SimplifiedType>)
106106
-> Result<Inserted, OverlapError>
107107
{
108+
let mut last_lint = None;
109+
108110
for slot in match simplified_self {
109111
Some(sty) => self.filtered_mut(sty),
110112
None => self.iter_mut(),
111113
} {
112114
let possible_sibling = *slot;
113115

116+
let overlap_error = |overlap: traits::coherence::OverlapResult| {
117+
// overlap, but no specialization; error out
118+
let trait_ref = overlap.impl_header.trait_ref.unwrap();
119+
let self_ty = trait_ref.self_ty();
120+
OverlapError {
121+
with_impl: possible_sibling,
122+
trait_desc: trait_ref.to_string(),
123+
// only report the Self type if it has at least
124+
// some outer concrete shell; otherwise, it's
125+
// not adding much information.
126+
self_desc: if self_ty.has_concrete_skeleton() {
127+
Some(self_ty.to_string())
128+
} else {
129+
None
130+
},
131+
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
132+
}
133+
};
134+
114135
let tcx = tcx.global_tcx();
115136
let (le, ge) = tcx.infer_ctxt().enter(|infcx| {
116137
let overlap = traits::overlapping_impls(&infcx,
117138
possible_sibling,
118-
impl_def_id);
139+
impl_def_id,
140+
traits::IntercrateMode::Issue43355);
119141
if let Some(overlap) = overlap {
120142
if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
121143
return Ok((false, false));
@@ -125,22 +147,7 @@ impl<'a, 'gcx, 'tcx> Children {
125147
let ge = tcx.specializes((possible_sibling, impl_def_id));
126148

127149
if le == ge {
128-
// overlap, but no specialization; error out
129-
let trait_ref = overlap.impl_header.trait_ref.unwrap();
130-
let self_ty = trait_ref.self_ty();
131-
Err(OverlapError {
132-
with_impl: possible_sibling,
133-
trait_desc: trait_ref.to_string(),
134-
// only report the Self type if it has at least
135-
// some outer concrete shell; otherwise, it's
136-
// not adding much information.
137-
self_desc: if self_ty.has_concrete_skeleton() {
138-
Some(self_ty.to_string())
139-
} else {
140-
None
141-
},
142-
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
143-
})
150+
Err(overlap_error(overlap))
144151
} else {
145152
Ok((le, ge))
146153
}
@@ -163,14 +170,27 @@ impl<'a, 'gcx, 'tcx> Children {
163170
*slot = impl_def_id;
164171
return Ok(Inserted::Replaced(possible_sibling));
165172
} else {
173+
if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
174+
tcx.infer_ctxt().enter(|infcx| {
175+
if let Some(overlap) = traits::overlapping_impls(
176+
&infcx,
177+
possible_sibling,
178+
impl_def_id,
179+
traits::IntercrateMode::Fixed)
180+
{
181+
last_lint = Some(overlap_error(overlap));
182+
}
183+
});
184+
}
185+
166186
// no overlap (error bailed already via ?)
167187
}
168188
}
169189

170190
// no overlap with any potential siblings, so add as a new sibling
171191
debug!("placing as new sibling");
172192
self.insert_blindly(tcx, impl_def_id);
173-
Ok(Inserted::BecameNewSibling)
193+
Ok(Inserted::BecameNewSibling(last_lint))
174194
}
175195

176196
fn iter_mut(&'a mut self) -> Box<Iterator<Item = &'a mut DefId> + 'a> {
@@ -199,7 +219,7 @@ impl<'a, 'gcx, 'tcx> Graph {
199219
pub fn insert(&mut self,
200220
tcx: TyCtxt<'a, 'gcx, 'tcx>,
201221
impl_def_id: DefId)
202-
-> Result<(), OverlapError> {
222+
-> Result<Option<OverlapError>, OverlapError> {
203223
assert!(impl_def_id.is_local());
204224

205225
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
@@ -220,10 +240,11 @@ impl<'a, 'gcx, 'tcx> Graph {
220240
self.parent.insert(impl_def_id, trait_def_id);
221241
self.children.entry(trait_def_id).or_insert(Children::new())
222242
.insert_blindly(tcx, impl_def_id);
223-
return Ok(());
243+
return Ok(None);
224244
}
225245

226246
let mut parent = trait_def_id;
247+
let mut last_lint = None;
227248
let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false);
228249

229250
// Descend the specialization tree, where `parent` is the current parent node
@@ -234,7 +255,8 @@ impl<'a, 'gcx, 'tcx> Graph {
234255
.insert(tcx, impl_def_id, simplified)?;
235256

236257
match insert_result {
237-
BecameNewSibling => {
258+
BecameNewSibling(opt_lint) => {
259+
last_lint = opt_lint;
238260
break;
239261
}
240262
Replaced(new_child) => {
@@ -251,7 +273,7 @@ impl<'a, 'gcx, 'tcx> Graph {
251273
}
252274

253275
self.parent.insert(impl_def_id, parent);
254-
Ok(())
276+
Ok(last_lint)
255277
}
256278

257279
/// Insert cached metadata mapping from a child impl back to its parent.

src/librustc_lint/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
243243
id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
244244
reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
245245
},
246+
FutureIncompatibleInfo {
247+
id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS),
248+
reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
249+
},
246250
]);
247251

248252
// Register renamed and removed lints

0 commit comments

Comments
 (0)