@@ -13,15 +13,13 @@ use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Varian
13
13
use rustc_middle:: hir:: map:: Map ;
14
14
use rustc_middle:: middle:: privacy:: AccessLevels ;
15
15
use rustc_middle:: middle:: stability:: { DeprecationEntry , Index } ;
16
- use rustc_middle:: ty:: query:: Providers ;
17
- use rustc_middle:: ty:: TyCtxt ;
16
+ use rustc_middle:: ty:: { self , query:: Providers , TyCtxt } ;
18
17
use rustc_session:: lint;
19
18
use rustc_session:: lint:: builtin:: INEFFECTIVE_UNSTABLE_TRAIT_IMPL ;
20
19
use rustc_session:: parse:: feature_err;
21
20
use rustc_session:: Session ;
22
21
use rustc_span:: symbol:: { sym, Symbol } ;
23
- use rustc_span:: Span ;
24
- use rustc_trait_selection:: traits:: misc:: can_type_implement_copy;
22
+ use rustc_span:: { Span , DUMMY_SP } ;
25
23
26
24
use std:: cmp:: Ordering ;
27
25
use std:: mem:: replace;
@@ -711,27 +709,35 @@ impl Visitor<'tcx> for Checker<'tcx> {
711
709
// so semi-randomly perform it here in stability.rs
712
710
hir:: ItemKind :: Union ( ..) if !self . tcx . features ( ) . untagged_unions => {
713
711
let def_id = self . tcx . hir ( ) . local_def_id ( item. hir_id ) ;
714
- let adt_def = self . tcx . adt_def ( def_id) ;
715
712
let ty = self . tcx . type_of ( def_id) ;
713
+ let ( adt_def, substs) = match ty. kind ( ) {
714
+ ty:: Adt ( adt_def, substs) => ( adt_def, substs) ,
715
+ _ => bug ! ( ) ,
716
+ } ;
716
717
717
- if adt_def. has_dtor ( self . tcx ) {
718
- feature_err (
719
- & self . tcx . sess . parse_sess ,
720
- sym:: untagged_unions,
721
- item. span ,
722
- "unions with `Drop` implementations are unstable" ,
723
- )
724
- . emit ( ) ;
725
- } else {
726
- let param_env = self . tcx . param_env ( def_id) ;
727
- if can_type_implement_copy ( self . tcx , param_env, ty) . is_err ( ) {
728
- feature_err (
729
- & self . tcx . sess . parse_sess ,
730
- sym:: untagged_unions,
731
- item. span ,
732
- "unions with non-`Copy` fields are unstable" ,
733
- )
734
- . emit ( ) ;
718
+ // Non-`Copy` fields are unstable, except for `ManuallyDrop`.
719
+ let param_env = self . tcx . param_env ( def_id) ;
720
+ for field in & adt_def. non_enum_variant ( ) . fields {
721
+ let field_ty = field. ty ( self . tcx , substs) ;
722
+ if !field_ty. ty_adt_def ( ) . map_or ( false , |adt_def| adt_def. is_manually_drop ( ) )
723
+ && !field_ty. is_copy_modulo_regions ( self . tcx . at ( DUMMY_SP ) , param_env)
724
+ {
725
+ if field_ty. needs_drop ( self . tcx , param_env) {
726
+ // Avoid duplicate error: This will error later anyway because fields
727
+ // that need drop are not allowed.
728
+ self . tcx . sess . delay_span_bug (
729
+ item. span ,
730
+ "union should have been rejected due to potentially dropping field" ,
731
+ ) ;
732
+ } else {
733
+ feature_err (
734
+ & self . tcx . sess . parse_sess ,
735
+ sym:: untagged_unions,
736
+ self . tcx . def_span ( field. did ) ,
737
+ "unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable" ,
738
+ )
739
+ . emit ( ) ;
740
+ }
735
741
}
736
742
}
737
743
}
0 commit comments