]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/wf.rs
debuginfo: Make debuginfo source location assignment more stable (Pt. 1)
[rust.git] / src / librustc_typeck / check / wf.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use astconv::AstConv;
12 use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
13 use CrateCtxt;
14 use middle::region;
15 use middle::subst;
16 use middle::traits;
17 use middle::ty::{self, Ty};
18 use middle::ty::liberate_late_bound_regions;
19 use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
20 use util::ppaux::Repr;
21
22 use std::collections::HashSet;
23 use syntax::ast;
24 use syntax::ast_util::{local_def};
25 use syntax::attr;
26 use syntax::codemap::Span;
27 use syntax::parse::token;
28 use syntax::visit;
29 use syntax::visit::Visitor;
30
31 pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
32     ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
33     cache: HashSet<Ty<'tcx>>
34 }
35
36 impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
37     pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) -> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
38         CheckTypeWellFormedVisitor { ccx: ccx, cache: HashSet::new() }
39     }
40
41     /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
42     /// well-formed, meaning that they do not require any constraints not declared in the struct
43     /// definition itself. For example, this definition would be illegal:
44     ///
45     ///     struct Ref<'a, T> { x: &'a T }
46     ///
47     /// because the type did not declare that `T:'a`.
48     ///
49     /// We do this check as a pre-pass before checking fn bodies because if these constraints are
50     /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
51     /// the types first.
52     fn check_item_well_formed(&mut self, item: &ast::Item) {
53         let ccx = self.ccx;
54         debug!("check_item_well_formed(it.id={}, it.ident={})",
55                item.id,
56                ty::item_path_str(ccx.tcx, local_def(item.id)));
57
58         match item.node {
59             /// Right now we check that every default trait implementation
60             /// has an implementation of itself. Basically, a case like:
61             ///
62             /// `impl Trait for T {}`
63             ///
64             /// has a requirement of `T: Trait` which was required for default
65             /// method implementations. Although this could be improved now that
66             /// there's a better infrastructure in place for this, it's being left
67             /// for a follow-up work.
68             ///
69             /// Since there's such a requirement, we need to check *just* positive
70             /// implementations, otherwise things like:
71             ///
72             /// impl !Send for T {}
73             ///
74             /// won't be allowed unless there's an *explicit* implementation of `Send`
75             /// for `T`
76             ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => {
77                 self.check_impl(item);
78             }
79             ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(ref tref), _, _) => {
80                 let trait_ref = ty::node_id_to_trait_ref(ccx.tcx, tref.ref_id);
81                 match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
82                     Some(ty::BoundSend) | Some(ty::BoundSync) => {}
83                     Some(_) | None => {
84                         ccx.tcx.sess.span_err(
85                             item.span,
86                             format!("negative impls are currently \
87                                      allowed just for `Send` and `Sync`").as_slice())
88                     }
89                 }
90             }
91             ast::ItemFn(..) => {
92                 self.check_item_type(item);
93             }
94             ast::ItemStatic(..) => {
95                 self.check_item_type(item);
96             }
97             ast::ItemConst(..) => {
98                 self.check_item_type(item);
99             }
100             ast::ItemStruct(ref struct_def, _) => {
101                 self.check_type_defn(item, |fcx| {
102                     vec![struct_variant(fcx, &**struct_def)]
103                 });
104             }
105             ast::ItemEnum(ref enum_def, _) => {
106                 self.check_type_defn(item, |fcx| {
107                     enum_variants(fcx, enum_def)
108                 });
109             }
110             ast::ItemTrait(..) => {
111                 let trait_def =
112                     ty::lookup_trait_def(ccx.tcx, local_def(item.id));
113                 reject_non_type_param_bounds(
114                     ccx.tcx,
115                     item.span,
116                     &trait_def.generics);
117             }
118             _ => {}
119         }
120     }
121
122     fn with_fcx<F>(&mut self, item: &ast::Item, mut f: F) where
123         F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>),
124     {
125         let ccx = self.ccx;
126         let item_def_id = local_def(item.id);
127         let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id);
128         reject_non_type_param_bounds(ccx.tcx, item.span, &type_scheme.generics);
129         let param_env =
130             ty::construct_parameter_environment(ccx.tcx,
131                                                 &type_scheme.generics,
132                                                 item.id);
133         let inh = Inherited::new(ccx.tcx, param_env);
134         let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id);
135         f(self, &fcx);
136         vtable::select_all_fcx_obligations_or_error(&fcx);
137         regionck::regionck_item(&fcx, item);
138     }
139
140     /// In a type definition, we check that to ensure that the types of the fields are well-formed.
141     fn check_type_defn<F>(&mut self, item: &ast::Item, mut lookup_fields: F) where
142         F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>,
143     {
144         self.with_fcx(item, |this, fcx| {
145             let variants = lookup_fields(fcx);
146             let mut bounds_checker = BoundsChecker::new(fcx,
147                                                         item.span,
148                                                         region::CodeExtent::from_node_id(item.id),
149                                                         Some(&mut this.cache));
150             for variant in variants.iter() {
151                 for field in variant.fields.iter() {
152                     // Regions are checked below.
153                     bounds_checker.check_traits_in_ty(field.ty);
154                 }
155
156                 // For DST, all intermediate types must be sized.
157                 if variant.fields.len() > 0 {
158                     for field in variant.fields.init().iter() {
159                         fcx.register_builtin_bound(
160                             field.ty,
161                             ty::BoundSized,
162                             traits::ObligationCause::new(field.span,
163                                                          fcx.body_id,
164                                                          traits::FieldSized));
165                     }
166                 }
167             }
168
169             let field_tys: Vec<Ty> =
170                 variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect();
171
172             regionck::regionck_ensure_component_tys_wf(
173                 fcx, item.span, field_tys.as_slice());
174         });
175     }
176
177     fn check_item_type(&mut self,
178                        item: &ast::Item)
179     {
180         self.with_fcx(item, |this, fcx| {
181             let mut bounds_checker = BoundsChecker::new(fcx,
182                                                         item.span,
183                                                         region::CodeExtent::from_node_id(item.id),
184                                                         Some(&mut this.cache));
185
186             let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
187             let item_ty = fcx.instantiate_type_scheme(item.span,
188                                                       &fcx.inh.param_env.free_substs,
189                                                       &type_scheme.ty);
190
191             bounds_checker.check_traits_in_ty(item_ty);
192         });
193     }
194
195     fn check_impl(&mut self,
196                   item: &ast::Item)
197     {
198         self.with_fcx(item, |this, fcx| {
199             let item_scope = region::CodeExtent::from_node_id(item.id);
200
201             let mut bounds_checker = BoundsChecker::new(fcx,
202                                                         item.span,
203                                                         item_scope,
204                                                         Some(&mut this.cache));
205
206             // Find the impl self type as seen from the "inside" --
207             // that is, with all type parameters converted from bound
208             // to free.
209             let self_ty = ty::node_id_to_type(fcx.tcx(), item.id);
210             let self_ty = fcx.instantiate_type_scheme(item.span,
211                                                       &fcx.inh.param_env.free_substs,
212                                                       &self_ty);
213
214             bounds_checker.check_traits_in_ty(self_ty);
215
216             // Similarly, obtain an "inside" reference to the trait
217             // that the impl implements.
218             let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) {
219                 None => { return; }
220                 Some(t) => { t }
221             };
222
223             let trait_ref = fcx.instantiate_type_scheme(item.span,
224                                                         &fcx.inh.param_env.free_substs,
225                                                         &trait_ref);
226
227             // There are special rules that apply to drop.
228             if
229                 fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) &&
230                 !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor")
231             {
232                 match self_ty.sty {
233                     ty::ty_struct(def_id, _) |
234                     ty::ty_enum(def_id, _) => {
235                         check_struct_safe_for_destructor(fcx, item.span, def_id);
236                     }
237                     _ => {
238                         // Coherence already reports an error in this case.
239                     }
240                 }
241             }
242
243             if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id) {
244                 // This is checked in coherence.
245                 return
246             }
247
248             // We are stricter on the trait-ref in an impl than the
249             // self-type.  In particular, we enforce region
250             // relationships. The reason for this is that (at least
251             // presently) "applying" an impl does not require that the
252             // application site check the well-formedness constraints on the
253             // trait reference. Instead, this is done at the impl site.
254             // Arguably this is wrong and we should treat the trait-reference
255             // the same way as we treat the self-type.
256             bounds_checker.check_trait_ref(&*trait_ref);
257
258             let cause =
259                 traits::ObligationCause::new(
260                     item.span,
261                     fcx.body_id,
262                     traits::ItemObligation(trait_ref.def_id));
263
264             // Find the supertrait bounds. This will add `int:Bar`.
265             let poly_trait_ref = ty::Binder(trait_ref);
266             let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref);
267             let predicates = {
268                 let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx);
269                 traits::normalize(selcx, cause.clone(), &predicates)
270             };
271             for predicate in predicates.value.into_iter() {
272                 fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate));
273             }
274             for obligation in predicates.obligations.into_iter() {
275                 fcx.register_predicate(obligation);
276             }
277         });
278     }
279 }
280
281 // Reject any predicates that do not involve a type parameter.
282 fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
283                                       span: Span,
284                                       generics: &ty::Generics<'tcx>) {
285
286     for predicate in generics.predicates.iter() {
287         match predicate {
288             &ty::Predicate::Trait(ty::Binder(ref tr)) => {
289                 let found_param = tr.input_types().iter()
290                                     .flat_map(|ty| ty.walk())
291                                     .any(is_ty_param);
292                 if !found_param { report_bound_error(tcx, span, tr.self_ty() )}
293             }
294             &ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(ty, _))) => {
295                 let found_param = ty.walk().any(|t| is_ty_param(t));
296                 if !found_param { report_bound_error(tcx, span, ty) }
297             }
298             _ => {}
299         };
300     }
301
302     fn report_bound_error<'t>(tcx: &ty::ctxt<'t>,
303                           span: Span,
304                           bounded_ty: ty::Ty<'t>) {
305         tcx.sess.span_err(
306             span,
307             format!("cannot bound type `{}`, where clause \
308                 bounds may only be attached to types involving \
309                 type parameters",
310                 bounded_ty.repr(tcx)).as_slice())
311     }
312
313     fn is_ty_param(ty: ty::Ty) -> bool {
314         match &ty.sty {
315             &ty::sty::ty_param(_) => true,
316             _ => false
317         }
318     }
319 }
320
321 fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>,
322                                           span: Span,
323                                           generics: &ty::Generics<'tcx>) {
324     let impl_params = generics.types.get_slice(subst::TypeSpace).iter()
325         .map(|tp| tp.name).collect::<HashSet<_>>();
326
327     for method_param in generics.types.get_slice(subst::FnSpace).iter() {
328         if impl_params.contains(&method_param.name) {
329             tcx.sess.span_err(
330                 span,
331                 &*format!("type parameter `{}` shadows another type parameter of the same name",
332                           token::get_name(method_param.name)));
333         }
334     }
335 }
336
337 impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
338     fn visit_item(&mut self, i: &ast::Item) {
339         self.check_item_well_formed(i);
340         visit::walk_item(self, i);
341     }
342
343     fn visit_fn(&mut self,
344                 fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
345                 b: &'v ast::Block, span: Span, id: ast::NodeId) {
346         match fk {
347             visit::FkFnBlock | visit::FkItemFn(..) => {}
348             visit::FkMethod(..) => {
349                 match ty::impl_or_trait_item(self.ccx.tcx, local_def(id)) {
350                     ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
351                         reject_shadowing_type_parameters(self.ccx.tcx, span, &ty_method.generics)
352                     }
353                     _ => {}
354                 }
355             }
356         }
357         visit::walk_fn(self, fk, fd, b, span)
358     }
359
360     fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
361         match t {
362             &ast::TraitItem::ProvidedMethod(_) |
363             &ast::TraitItem::TypeTraitItem(_) => {},
364             &ast::TraitItem::RequiredMethod(ref method) => {
365                 match ty::impl_or_trait_item(self.ccx.tcx, local_def(method.id)) {
366                     ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
367                         reject_non_type_param_bounds(
368                             self.ccx.tcx,
369                             method.span,
370                             &ty_method.generics);
371                         reject_shadowing_type_parameters(
372                             self.ccx.tcx,
373                             method.span,
374                             &ty_method.generics);
375                     }
376                     _ => {}
377                 }
378             }
379         }
380
381         visit::walk_trait_item(self, t)
382     }
383 }
384
385 pub struct BoundsChecker<'cx,'tcx:'cx> {
386     fcx: &'cx FnCtxt<'cx,'tcx>,
387     span: Span,
388     scope: region::CodeExtent,
389     binding_count: uint,
390     cache: Option<&'cx mut HashSet<Ty<'tcx>>>,
391 }
392
393 impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
394     pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
395                span: Span,
396                scope: region::CodeExtent,
397                cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
398                -> BoundsChecker<'cx,'tcx> {
399         BoundsChecker { fcx: fcx, span: span, scope: scope,
400                         cache: cache, binding_count: 0 }
401     }
402
403     /// Given a trait ref like `A : Trait<B>`, where `Trait` is defined as (say):
404     ///
405     ///     trait Trait<B:OtherTrait> : Copy { ... }
406     ///
407     /// This routine will check that `B : OtherTrait` and `A : Trait<B>`. It will also recursively
408     /// check that the types `A` and `B` are well-formed.
409     ///
410     /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated
411     /// to the point where impl `A : Trait<B>` is implemented).
412     pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
413         let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
414
415         let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics);
416
417         self.fcx.add_obligations_for_parameters(
418             traits::ObligationCause::new(
419                 self.span,
420                 self.fcx.body_id,
421                 traits::ItemObligation(trait_ref.def_id)),
422             &bounds);
423
424         for &ty in trait_ref.substs.types.iter() {
425             self.check_traits_in_ty(ty);
426         }
427     }
428
429     pub fn check_ty(&mut self, ty: Ty<'tcx>) {
430         ty.fold_with(self);
431     }
432
433     fn check_traits_in_ty(&mut self, ty: Ty<'tcx>) {
434         // When checking types outside of a type def'n, we ignore
435         // region obligations. See discussion below in fold_ty().
436         self.binding_count += 1;
437         ty.fold_with(self);
438         self.binding_count -= 1;
439     }
440 }
441
442 impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
443     fn tcx(&self) -> &ty::ctxt<'tcx> {
444         self.fcx.tcx()
445     }
446
447     fn fold_binder<T>(&mut self, binder: &ty::Binder<T>) -> ty::Binder<T>
448         where T : TypeFoldable<'tcx> + Repr<'tcx>
449     {
450         self.binding_count += 1;
451         let value = liberate_late_bound_regions(self.fcx.tcx(), self.scope, binder);
452         debug!("BoundsChecker::fold_binder: late-bound regions replaced: {}",
453                value.repr(self.tcx()));
454         let value = value.fold_with(self);
455         self.binding_count -= 1;
456         ty::Binder(value)
457     }
458
459     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
460         debug!("BoundsChecker t={}",
461                t.repr(self.tcx()));
462
463         match self.cache {
464             Some(ref mut cache) => {
465                 if !cache.insert(t) {
466                     // Already checked this type! Don't check again.
467                     debug!("cached");
468                     return t;
469                 }
470             }
471             None => { }
472         }
473
474         match t.sty{
475             ty::ty_struct(type_id, substs) |
476             ty::ty_enum(type_id, substs) => {
477                 let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
478                 let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics);
479
480                 if self.binding_count == 0 {
481                     self.fcx.add_obligations_for_parameters(
482                         traits::ObligationCause::new(self.span,
483                                                      self.fcx.body_id,
484                                                      traits::ItemObligation(type_id)),
485                         &bounds);
486                 } else {
487                     // There are two circumstances in which we ignore
488                     // region obligations.
489                     //
490                     // The first is when we are inside of a closure
491                     // type. This is because in that case the region
492                     // obligations for the parameter types are things
493                     // that the closure body gets to assume and the
494                     // caller must prove at the time of call. In other
495                     // words, if there is a type like `<'a, 'b> | &'a
496                     // &'b int |`, it is well-formed, and caller will
497                     // have to show that `'b : 'a` at the time of
498                     // call.
499                     //
500                     // The second is when we are checking for
501                     // well-formedness outside of a type def'n or fn
502                     // body. This is for a similar reason: in general,
503                     // we only do WF checking for regions in the
504                     // result of expressions and type definitions, so
505                     // to as allow for implicit where clauses.
506                     //
507                     // (I believe we should do the same for traits, but
508                     // that will require an RFC. -nmatsakis)
509                     let bounds = filter_to_trait_obligations(bounds);
510                     self.fcx.add_obligations_for_parameters(
511                         traits::ObligationCause::new(self.span,
512                                                      self.fcx.body_id,
513                                                      traits::ItemObligation(type_id)),
514                         &bounds);
515                 }
516
517                 self.fold_substs(substs);
518             }
519             _ => {
520                 super_fold_ty(self, t);
521             }
522         }
523
524         t // we're not folding to produce a new type, so just return `t` here
525     }
526 }
527
528 ///////////////////////////////////////////////////////////////////////////
529 // ADT
530
531 struct AdtVariant<'tcx> {
532     fields: Vec<AdtField<'tcx>>,
533 }
534
535 struct AdtField<'tcx> {
536     ty: Ty<'tcx>,
537     span: Span,
538 }
539
540 fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
541                             struct_def: &ast::StructDef)
542                             -> AdtVariant<'tcx> {
543     let fields =
544         struct_def.fields
545         .iter()
546         .map(|field| {
547             let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id);
548             let field_ty = fcx.instantiate_type_scheme(field.span,
549                                                        &fcx.inh.param_env.free_substs,
550                                                        &field_ty);
551             AdtField { ty: field_ty, span: field.span }
552         })
553         .collect();
554     AdtVariant { fields: fields }
555 }
556
557 fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
558                            enum_def: &ast::EnumDef)
559                            -> Vec<AdtVariant<'tcx>> {
560     enum_def.variants.iter()
561         .map(|variant| {
562             match variant.node.kind {
563                 ast::TupleVariantKind(ref args) if args.len() > 0 => {
564                     let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id);
565
566                     // the regions in the argument types come from the
567                     // enum def'n, and hence will all be early bound
568                     let arg_tys =
569                         ty::assert_no_late_bound_regions(
570                             fcx.tcx(), &ty::ty_fn_args(ctor_ty));
571                     AdtVariant {
572                         fields: args.iter().enumerate().map(|(index, arg)| {
573                             let arg_ty = arg_tys[index];
574                             let arg_ty =
575                                 fcx.instantiate_type_scheme(variant.span,
576                                                             &fcx.inh.param_env.free_substs,
577                                                             &arg_ty);
578                             AdtField {
579                                 ty: arg_ty,
580                                 span: arg.ty.span
581                             }
582                         }).collect()
583                     }
584                 }
585                 ast::TupleVariantKind(_) => {
586                     AdtVariant {
587                         fields: Vec::new()
588                     }
589                 }
590                 ast::StructVariantKind(ref struct_def) => {
591                     struct_variant(fcx, &**struct_def)
592                 }
593             }
594         })
595         .collect()
596 }
597
598 fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>)
599                                      -> ty::GenericBounds<'tcx>
600 {
601     let mut result = ty::GenericBounds::empty();
602     for (space, _, predicate) in bounds.predicates.iter_enumerated() {
603         match *predicate {
604             ty::Predicate::Trait(..) |
605             ty::Predicate::Projection(..) => {
606                 result.predicates.push(space, predicate.clone())
607             }
608             ty::Predicate::Equate(..) |
609             ty::Predicate::TypeOutlives(..) |
610             ty::Predicate::RegionOutlives(..) => {
611             }
612         }
613     }
614     result
615 }
616
617 ///////////////////////////////////////////////////////////////////////////
618 // Special drop trait checking
619
620 fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
621                                               span: Span,
622                                               struct_did: ast::DefId) {
623     let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did);
624     if struct_tpt.generics.has_type_params(subst::TypeSpace)
625         || struct_tpt.generics.has_region_params(subst::TypeSpace)
626     {
627         span_err!(fcx.tcx().sess, span, E0141,
628                   "cannot implement a destructor on a structure \
629                    with type parameters");
630         span_note!(fcx.tcx().sess, span,
631                    "use \"#[unsafe_destructor]\" on the implementation \
632                     to force the compiler to allow this");
633     }
634 }