@@ -13,15 +13,13 @@ use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Varian
1313use rustc_middle:: hir:: map:: Map ;
1414use rustc_middle:: middle:: privacy:: AccessLevels ;
1515use 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 } ;
1817use rustc_session:: lint;
1918use rustc_session:: lint:: builtin:: INEFFECTIVE_UNSTABLE_TRAIT_IMPL ;
2019use rustc_session:: parse:: feature_err;
2120use rustc_session:: Session ;
2221use 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 } ;
2523
2624use std:: cmp:: Ordering ;
2725use std:: mem:: replace;
@@ -711,27 +709,35 @@ impl Visitor<'tcx> for Checker<'tcx> {
711709 // so semi-randomly perform it here in stability.rs
712710 hir:: ItemKind :: Union ( ..) if !self . tcx . features ( ) . untagged_unions => {
713711 let def_id = self . tcx . hir ( ) . local_def_id ( item. hir_id ) ;
714- let adt_def = self . tcx . adt_def ( def_id) ;
715712 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+ } ;
716717
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+ }
735741 }
736742 }
737743 }
0 commit comments