Skip to content

Commit 7e6e64b

Browse files
committed
Rollup merge of rust-lang#28681 - arielb1:destructor-fixes, r=eddyb
Fixes rust-lang#28568 r? @eddyb
2 parents 5f90904 + 9a86713 commit 7e6e64b

36 files changed

+172
-84
lines changed

src/librustc/middle/infer/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use std::rc::Rc;
4343
use syntax::ast;
4444
use syntax::codemap;
4545
use syntax::codemap::{Span, DUMMY_SP};
46-
use util::nodemap::{FnvHashMap, NodeMap};
46+
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
4747

4848
use self::combine::CombineFields;
4949
use self::region_inference::{RegionVarBindings, RegionSnapshot};
@@ -92,6 +92,10 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
9292

9393
pub fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
9494

95+
// the set of predicates on which errors have been reported, to
96+
// avoid reporting the same error twice.
97+
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
98+
9599
// This is a temporary field used for toggling on normalization in the inference context,
96100
// as we move towards the approach described here:
97101
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
@@ -374,6 +378,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
374378
region_vars: RegionVarBindings::new(tcx),
375379
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
376380
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
381+
reported_trait_errors: RefCell::new(FnvHashSet()),
377382
normalize: false,
378383
err_count_on_creation: tcx.sess.err_count()
379384
}

src/librustc/middle/reachable.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -348,13 +348,17 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
348348
// this properly would result in the necessity of computing *type*
349349
// reachability, which might result in a compile time loss.
350350
fn mark_destructors_reachable(&mut self) {
351-
for adt in self.tcx.adt_defs() {
352-
if let Some(destructor_def_id) = adt.destructor() {
353-
if destructor_def_id.is_local() {
354-
self.reachable_symbols.insert(destructor_def_id.node);
351+
let drop_trait = match self.tcx.lang_items.drop_trait() {
352+
Some(id) => self.tcx.lookup_trait_def(id), None => { return }
353+
};
354+
drop_trait.for_each_impl(self.tcx, |drop_impl| {
355+
for destructor in &self.tcx.impl_items.borrow()[&drop_impl] {
356+
let destructor_did = destructor.def_id();
357+
if destructor_did.is_local() {
358+
self.reachable_symbols.insert(destructor_did.node);
355359
}
356360
}
357-
}
361+
})
358362
}
359363
}
360364

src/librustc/middle/traits/error_reporting.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,32 @@ use middle::def_id::DefId;
2828
use middle::infer::InferCtxt;
2929
use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty};
3030
use middle::ty::fold::TypeFoldable;
31-
use std::collections::HashMap;
31+
use util::nodemap::{FnvHashMap, FnvHashSet};
32+
3233
use std::fmt;
3334
use syntax::codemap::Span;
3435
use syntax::attr::{AttributeMethods, AttrMetaMethods};
3536

37+
#[derive(Debug, PartialEq, Eq, Hash)]
38+
pub struct TraitErrorKey<'tcx> {
39+
is_warning: bool,
40+
span: Span,
41+
predicate: ty::Predicate<'tcx>
42+
}
43+
44+
impl<'tcx> TraitErrorKey<'tcx> {
45+
fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>,
46+
e: &FulfillmentError<'tcx>) -> Self {
47+
let predicate =
48+
infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
49+
TraitErrorKey {
50+
is_warning: is_warning(&e.obligation),
51+
span: e.obligation.cause.span,
52+
predicate: infcx.tcx.erase_regions(&predicate)
53+
}
54+
}
55+
}
56+
3657
pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
3758
errors: &Vec<FulfillmentError<'tcx>>) {
3859
for error in errors {
@@ -42,6 +63,13 @@ pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
4263

4364
fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
4465
error: &FulfillmentError<'tcx>) {
66+
let error_key = TraitErrorKey::from_error(infcx, error);
67+
debug!("report_fulfillment_errors({:?}) - key={:?}",
68+
error, error_key);
69+
if !infcx.reported_trait_errors.borrow_mut().insert(error_key) {
70+
debug!("report_fulfillment_errors: skipping duplicate");
71+
return;
72+
}
4573
match error.code {
4674
FulfillmentErrorCode::CodeSelectionError(ref e) => {
4775
report_selection_error(infcx, &error.obligation, e);
@@ -97,7 +125,7 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
97125
(gen.name.as_str().to_string(),
98126
trait_ref.substs.types.get(param, i)
99127
.to_string())
100-
}).collect::<HashMap<String, String>>();
128+
}).collect::<FnvHashMap<String, String>>();
101129
generic_map.insert("Self".to_string(),
102130
trait_ref.self_ty().to_string());
103131
let parser = Parser::new(&istring);
@@ -308,7 +336,11 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
308336
"the trait `{}` cannot be made into an object",
309337
tcx.item_path_str(trait_def_id));
310338

339+
let mut reported_violations = FnvHashSet();
311340
for violation in violations {
341+
if !reported_violations.insert(violation.clone()) {
342+
continue;
343+
}
312344
match violation {
313345
ObjectSafetyViolation::SizedSelf => {
314346
tcx.sess.fileline_note(

src/librustc/middle/traits/fulfill.rs

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ pub struct FulfillmentContext<'tcx> {
4949
// than the `SelectionCache`: it avoids duplicate errors and
5050
// permits recursive obligations, which are often generated from
5151
// traits like `Send` et al.
52+
//
53+
// Note that because of type inference, a predicate can still
54+
// occur twice in the predicates list, for example when 2
55+
// initially-distinct type variables are unified after being
56+
// inserted. Deduplicating the predicate set on selection had a
57+
// significant performance cost the last time I checked.
5258
duplicate_set: FulfilledPredicates<'tcx>,
5359

5460
// A list of all obligations that have been registered with this

src/librustc/middle/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ use middle::subst;
2121
use middle::ty::{self, HasTypeFlags, Ty};
2222
use middle::ty::fold::TypeFoldable;
2323
use middle::infer::{self, fixup_err_to_string, InferCtxt};
24+
2425
use std::rc::Rc;
2526
use syntax::ast;
2627
use syntax::codemap::{Span, DUMMY_SP};
2728

29+
pub use self::error_reporting::TraitErrorKey;
2830
pub use self::error_reporting::report_fulfillment_errors;
2931
pub use self::error_reporting::report_overflow_error;
3032
pub use self::error_reporting::report_selection_error;

src/librustc/middle/traits/object_safety.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use middle::ty::{self, ToPolyTraitRef, Ty};
2727
use std::rc::Rc;
2828
use syntax::ast;
2929

30-
#[derive(Debug)]
30+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
3131
pub enum ObjectSafetyViolation<'tcx> {
3232
/// Self : Sized declared on the trait
3333
SizedSelf,

src/librustc/middle/ty/context.rs

-4
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,6 @@ pub struct ctxt<'tcx> {
245245
/// True if the variance has been computed yet; false otherwise.
246246
pub variance_computed: Cell<bool>,
247247

248-
/// A method will be in this list if and only if it is a destructor.
249-
pub destructors: RefCell<DefIdSet>,
250-
251248
/// Maps a DefId of a type to a list of its inherent impls.
252249
/// Contains implementations of methods that are inherent to a type.
253250
/// Methods in these implementations don't need to be exported.
@@ -475,7 +472,6 @@ impl<'tcx> ctxt<'tcx> {
475472
normalized_cache: RefCell::new(FnvHashMap()),
476473
lang_items: lang_items,
477474
provided_method_sources: RefCell::new(DefIdMap()),
478-
destructors: RefCell::new(DefIdSet()),
479475
inherent_impls: RefCell::new(DefIdMap()),
480476
impl_items: RefCell::new(DefIdMap()),
481477
used_unsafe: RefCell::new(NodeSet()),

src/librustc/middle/ty/mod.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,20 @@ impl<'tcx> Method<'tcx> {
272272
}
273273
}
274274

275+
impl<'tcx> PartialEq for Method<'tcx> {
276+
#[inline]
277+
fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id }
278+
}
279+
280+
impl<'tcx> Eq for Method<'tcx> {}
281+
282+
impl<'tcx> Hash for Method<'tcx> {
283+
#[inline]
284+
fn hash<H: Hasher>(&self, s: &mut H) {
285+
self.def_id.hash(s)
286+
}
287+
}
288+
275289
#[derive(Clone, Copy, Debug)]
276290
pub struct AssociatedConst<'tcx> {
277291
pub name: Name,
@@ -1681,7 +1695,6 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
16811695
}
16821696

16831697
pub fn set_destructor(&self, dtor: DefId) {
1684-
assert!(self.destructor.get().is_none());
16851698
self.destructor.set(Some(dtor));
16861699
}
16871700

@@ -2315,11 +2328,6 @@ impl<'tcx> ctxt<'tcx> {
23152328
self.lookup_adt_def_master(did)
23162329
}
23172330

2318-
/// Return the list of all interned ADT definitions
2319-
pub fn adt_defs(&self) -> Vec<AdtDef<'tcx>> {
2320-
self.adt_defs.borrow().values().cloned().collect()
2321-
}
2322-
23232331
/// Given the did of an item, returns its full set of predicates.
23242332
pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> {
23252333
lookup_locally_or_in_crate_store(

src/librustc_lint/builtin.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -1210,15 +1210,14 @@ impl LintPass for DropWithReprExtern {
12101210

12111211
impl LateLintPass for DropWithReprExtern {
12121212
fn check_crate(&mut self, ctx: &LateContext, _: &hir::Crate) {
1213-
for dtor_did in ctx.tcx.destructors.borrow().iter() {
1214-
let (drop_impl_did, dtor_self_type) =
1215-
if dtor_did.is_local() {
1216-
let impl_did = ctx.tcx.map.get_parent_did(dtor_did.node);
1217-
let ty = ctx.tcx.lookup_item_type(impl_did).ty;
1218-
(impl_did, ty)
1219-
} else {
1220-
continue;
1221-
};
1213+
let drop_trait = match ctx.tcx.lang_items.drop_trait() {
1214+
Some(id) => ctx.tcx.lookup_trait_def(id), None => { return }
1215+
};
1216+
drop_trait.for_each_impl(ctx.tcx, |drop_impl_did| {
1217+
if !drop_impl_did.is_local() {
1218+
return;
1219+
}
1220+
let dtor_self_type = ctx.tcx.lookup_item_type(drop_impl_did).ty;
12221221

12231222
match dtor_self_type.sty {
12241223
ty::TyEnum(self_type_def, _) |
@@ -1244,6 +1243,6 @@ impl LateLintPass for DropWithReprExtern {
12441243
}
12451244
_ => {}
12461245
}
1247-
}
1246+
})
12481247
}
12491248
}

src/librustc_typeck/check/method/confirm.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
620620
ty::TraitContainer(trait_def_id) => {
621621
callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
622622
}
623-
ty::ImplContainer(..) => {
624-
// Since `drop` is a trait method, we expect that any
625-
// potential calls to it will wind up in the other
626-
// arm. But just to be sure, check that the method id
627-
// does not appear in the list of destructors.
628-
assert!(!self.tcx().destructors.borrow().contains(&pick.item.def_id()));
629-
}
623+
ty::ImplContainer(..) => {}
630624
}
631625
}
632626

src/librustc_typeck/check/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -431,17 +431,19 @@ pub fn check_item_bodies(ccx: &CrateCtxt) {
431431
}
432432

433433
pub fn check_drop_impls(ccx: &CrateCtxt) {
434-
for drop_method_did in ccx.tcx.destructors.borrow().iter() {
435-
if drop_method_did.is_local() {
436-
let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node);
434+
let drop_trait = match ccx.tcx.lang_items.drop_trait() {
435+
Some(id) => ccx.tcx.lookup_trait_def(id), None => { return }
436+
};
437+
drop_trait.for_each_impl(ccx.tcx, |drop_impl_did| {
438+
if drop_impl_did.is_local() {
437439
match dropck::check_drop_impl(ccx.tcx, drop_impl_did) {
438440
Ok(()) => {}
439441
Err(()) => {
440442
assert!(ccx.tcx.sess.has_errors());
441443
}
442444
}
443445
}
444-
}
446+
});
445447

446448
ccx.tcx.sess.abort_if_errors();
447449
}

src/librustc_typeck/coherence/mod.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
126126
// Populate the table of destructors. It might seem a bit strange to
127127
// do this here, but it's actually the most convenient place, since
128128
// the coherence tables contain the trait -> type mappings.
129-
self.populate_destructor_table();
129+
self.populate_destructors();
130130

131131
// Check to make sure implementations of `Copy` are legal.
132132
self.check_implementations_of_copy();
@@ -286,7 +286,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
286286
// Destructors
287287
//
288288

289-
fn populate_destructor_table(&self) {
289+
fn populate_destructors(&self) {
290290
let tcx = self.crate_context.tcx;
291291
let drop_trait = match tcx.lang_items.drop_trait() {
292292
Some(id) => id, None => { return }
@@ -309,9 +309,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
309309
ty::TyEnum(type_def, _) |
310310
ty::TyStruct(type_def, _) => {
311311
type_def.set_destructor(method_def_id.def_id());
312-
tcx.destructors
313-
.borrow_mut()
314-
.insert(method_def_id.def_id());
315312
}
316313
_ => {
317314
// Destructors only work on nominal types.

src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs

-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,4 @@ fn ice<A>(a: A) {
3232
let r = loop {};
3333
r = r + a;
3434
//~^ ERROR not implemented
35-
//~| ERROR not implemented
3635
}

src/test/compile-fail/associated-types-path-2.rs

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ pub fn f1_int_uint() {
3939
pub fn f1_uint_uint() {
4040
f1(2u32, 4u32);
4141
//~^ ERROR the trait `Foo` is not implemented
42-
//~| ERROR the trait `Foo` is not implemented
4342
}
4443

4544
pub fn f1_uint_int() {

src/test/compile-fail/coerce-unsafe-to-closure.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
fn main() {
1212
let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
1313
//~^ ERROR E0277
14-
//~| ERROR E0277
1514
}

src/test/compile-fail/const-eval-overflow-4b.rs

-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ const A_I8_T
2323
: [u32; (i8::MAX as i8 + 1u8) as usize]
2424
//~^ ERROR mismatched types
2525
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
26-
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
2726
= [0; (i8::MAX as usize) + 1];
2827

2928
fn main() {
@@ -33,4 +32,3 @@ fn main() {
3332
fn foo<T:fmt::Debug>(x: T) {
3433
println!("{:?}", x);
3534
}
36-

src/test/compile-fail/fn-variance-1.rs

-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ fn main() {
2020
apply(&3, takes_imm);
2121
apply(&3, takes_mut);
2222
//~^ ERROR (values differ in mutability)
23-
//~| ERROR (values differ in mutability)
2423

2524
apply(&mut 3, takes_mut);
2625
apply(&mut 3, takes_imm);
2726
//~^ ERROR (values differ in mutability)
28-
//~| ERROR (values differ in mutability)
2927
}

src/test/compile-fail/for-loop-bogosity.rs

-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ pub fn main() {
2525
y: 2,
2626
};
2727
for x in bogus { //~ ERROR `core::iter::Iterator` is not implemented for the type `MyStruct`
28-
//~^ ERROR
29-
//~^^ ERROR
30-
// FIXME(#21528) not fulfilled obligation error should be reported once, not thrice
3128
drop(x);
3229
}
3330
}

src/test/compile-fail/indexing-requires-a-uint.rs

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
fn main() {
1515
fn bar<T>(_: T) {}
1616
[0][0u8]; //~ ERROR: the trait `core::ops::Index<u8>` is not implemented
17-
//~^ ERROR: the trait `core::ops::Index<u8>` is not implemented
1817

1918
[0][0]; // should infer to be a usize
2019

src/test/compile-fail/integral-indexing.rs

-8
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,13 @@ pub fn main() {
1414
v[3_usize];
1515
v[3];
1616
v[3u8]; //~ERROR the trait `core::ops::Index<u8>` is not implemented
17-
//~^ ERROR the trait `core::ops::Index<u8>` is not implemented
1817
v[3i8]; //~ERROR the trait `core::ops::Index<i8>` is not implemented
19-
//~^ ERROR the trait `core::ops::Index<i8>` is not implemented
2018
v[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
21-
//~^ ERROR the trait `core::ops::Index<u32>` is not implemented
2219
v[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
23-
//~^ ERROR the trait `core::ops::Index<i32>` is not implemented
2420
s.as_bytes()[3_usize];
2521
s.as_bytes()[3];
2622
s.as_bytes()[3u8]; //~ERROR the trait `core::ops::Index<u8>` is not implemented
27-
//~^ ERROR the trait `core::ops::Index<u8>` is not implemented
2823
s.as_bytes()[3i8]; //~ERROR the trait `core::ops::Index<i8>` is not implemented
29-
//~^ ERROR the trait `core::ops::Index<i8>` is not implemented
3024
s.as_bytes()[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
31-
//~^ ERROR the trait `core::ops::Index<u32>` is not implemented
3225
s.as_bytes()[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
33-
//~^ ERROR the trait `core::ops::Index<i32>` is not implemented
3426
}

0 commit comments

Comments
 (0)