@@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
66use rustc_errors:: MultiSpan ;
77use rustc_errors:: codes:: * ;
88use rustc_hir:: def:: { CtorKind , DefKind } ;
9- use rustc_hir:: { Node , intravisit} ;
9+ use rustc_hir:: { LangItem , Node , intravisit} ;
1010use rustc_infer:: infer:: { RegionVariableOrigin , TyCtxtInferExt } ;
1111use rustc_infer:: traits:: { Obligation , ObligationCauseCode } ;
1212use rustc_lint_defs:: builtin:: {
@@ -27,6 +27,7 @@ use rustc_session::lint::builtin::UNINHABITED_STATIC;
2727use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
2828use rustc_trait_selection:: error_reporting:: traits:: on_unimplemented:: OnUnimplementedDirective ;
2929use rustc_trait_selection:: traits;
30+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
3031use rustc_type_ir:: fold:: TypeFoldable ;
3132use tracing:: { debug, instrument} ;
3233use ty:: TypingMode ;
@@ -87,89 +88,76 @@ fn allowed_union_or_unsafe_field<'tcx>(
8788 typing_env : ty:: TypingEnv < ' tcx > ,
8889 span : Span ,
8990) -> bool {
90- // We don't just accept all !needs_drop fields, due to semver concerns.
91- let allowed = match ty. kind ( ) {
92- ty:: Ref ( ..) => true , // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
93- ty:: Tuple ( tys) => {
94- // allow tuples of allowed types
95- tys. iter ( ) . all ( |ty| allowed_union_or_unsafe_field ( tcx, ty, typing_env, span) )
96- }
97- ty:: Array ( elem, _len) => {
98- // Like `Copy`, we do *not* special-case length 0.
99- allowed_union_or_unsafe_field ( tcx, * elem, typing_env, span)
100- }
101- _ => {
102- // Fallback case: allow `ManuallyDrop` and things that are `Copy`,
103- // also no need to report an error if the type is unresolved.
104- ty. ty_adt_def ( ) . is_some_and ( |adt_def| adt_def. is_manually_drop ( ) )
105- || tcx. type_is_copy_modulo_regions ( typing_env, ty)
106- || ty. references_error ( )
107- }
108- } ;
109- if allowed && ty. needs_drop ( tcx, typing_env) {
110- // This should never happen. But we can get here e.g. in case of name resolution errors.
111- tcx. dcx ( )
112- . span_delayed_bug ( span, "we should never accept maybe-dropping union or unsafe fields" ) ;
91+ // HACK (not that bad of a hack don't worry): Some codegen tests don't even define proper
92+ // impls for `Copy`. Let's short-circuit here for this validity check, since a lot of them
93+ // use unions. We should eventually fix all the tests to define that lang item or use
94+ // minicore stubs.
95+ if ty. is_trivially_pure_clone_copy ( ) {
96+ return true ;
11397 }
114- allowed
98+ // If `BikeshedGuaranteedNoDrop` is not defined in a `#[no_core]` test, fall back to `Copy`.
99+ // This is an underapproximation of `BikeshedGuaranteedNoDrop`,
100+ let def_id = tcx
101+ . lang_items ( )
102+ . get ( LangItem :: BikeshedGuaranteedNoDrop )
103+ . unwrap_or_else ( || tcx. require_lang_item ( LangItem :: Copy , Some ( span) ) ) ;
104+ let Ok ( ty) = tcx. try_normalize_erasing_regions ( typing_env, ty) else {
105+ tcx. dcx ( ) . span_delayed_bug ( span, "could not normalize field type" ) ;
106+ return true ;
107+ } ;
108+ let ( infcx, param_env) = tcx. infer_ctxt ( ) . build_with_typing_env ( typing_env) ;
109+ infcx. predicate_must_hold_modulo_regions ( & Obligation :: new (
110+ tcx,
111+ ObligationCause :: dummy_with_span ( span) ,
112+ param_env,
113+ ty:: TraitRef :: new ( tcx, def_id, [ ty] ) ,
114+ ) )
115115}
116116
117117/// Check that the fields of the `union` do not need dropping.
118118fn check_union_fields ( tcx : TyCtxt < ' _ > , span : Span , item_def_id : LocalDefId ) -> bool {
119- let item_type = tcx. type_of ( item_def_id) . instantiate_identity ( ) ;
120- if let ty:: Adt ( def, args) = item_type. kind ( ) {
121- assert ! ( def. is_union( ) ) ;
122-
123- let typing_env = ty:: TypingEnv :: non_body_analysis ( tcx, item_def_id) ;
124- for field in & def. non_enum_variant ( ) . fields {
125- let Ok ( field_ty) = tcx. try_normalize_erasing_regions ( typing_env, field. ty ( tcx, args) )
126- else {
127- tcx. dcx ( ) . span_delayed_bug ( span, "could not normalize field type" ) ;
128- continue ;
129- } ;
119+ let def = tcx. adt_def ( item_def_id) ;
120+ assert ! ( def. is_union( ) ) ;
130121
131- if !allowed_union_or_unsafe_field ( tcx, field_ty, typing_env, span) {
132- let ( field_span, ty_span) = match tcx. hir ( ) . get_if_local ( field. did ) {
133- // We are currently checking the type this field came from, so it must be local.
134- Some ( Node :: Field ( field) ) => ( field. span , field. ty . span ) ,
135- _ => unreachable ! ( "mir field has to correspond to hir field" ) ,
136- } ;
137- tcx. dcx ( ) . emit_err ( errors:: InvalidUnionField {
138- field_span,
139- sugg : errors:: InvalidUnionFieldSuggestion {
140- lo : ty_span. shrink_to_lo ( ) ,
141- hi : ty_span. shrink_to_hi ( ) ,
142- } ,
143- note : ( ) ,
144- } ) ;
145- return false ;
146- }
122+ let typing_env = ty:: TypingEnv :: non_body_analysis ( tcx, item_def_id) ;
123+ let args = ty:: GenericArgs :: identity_for_item ( tcx, item_def_id) ;
124+
125+ for field in & def. non_enum_variant ( ) . fields {
126+ if !allowed_union_or_unsafe_field ( tcx, field. ty ( tcx, args) , typing_env, span) {
127+ let ( field_span, ty_span) = match tcx. hir ( ) . get_if_local ( field. did ) {
128+ // We are currently checking the type this field came from, so it must be local.
129+ Some ( Node :: Field ( field) ) => ( field. span , field. ty . span ) ,
130+ _ => unreachable ! ( "mir field has to correspond to hir field" ) ,
131+ } ;
132+ tcx. dcx ( ) . emit_err ( errors:: InvalidUnionField {
133+ field_span,
134+ sugg : errors:: InvalidUnionFieldSuggestion {
135+ lo : ty_span. shrink_to_lo ( ) ,
136+ hi : ty_span. shrink_to_hi ( ) ,
137+ } ,
138+ note : ( ) ,
139+ } ) ;
140+ return false ;
147141 }
148- } else {
149- span_bug ! ( span, "unions must be ty::Adt, but got {:?}" , item_type. kind( ) ) ;
150142 }
143+
151144 true
152145}
153146
154147/// Check that the unsafe fields do not need dropping.
155148fn check_unsafe_fields ( tcx : TyCtxt < ' _ > , item_def_id : LocalDefId ) {
156149 let span = tcx. def_span ( item_def_id) ;
157- let item_type = tcx. type_of ( item_def_id) . instantiate_identity ( ) ;
158- let ty:: Adt ( def, args) = item_type. kind ( ) else {
159- span_bug ! ( span, "structs/enums must be ty::Adt, but got {:?}" , item_type. kind( ) ) ;
160- } ;
150+ let def = tcx. adt_def ( item_def_id) ;
151+
161152 let typing_env = ty:: TypingEnv :: non_body_analysis ( tcx, item_def_id) ;
153+ let args = ty:: GenericArgs :: identity_for_item ( tcx, item_def_id) ;
154+
162155 for field in def. all_fields ( ) {
163156 if !field. safety . is_unsafe ( ) {
164157 continue ;
165158 }
166- let Ok ( field_ty) = tcx. try_normalize_erasing_regions ( typing_env, field. ty ( tcx, args) )
167- else {
168- tcx. dcx ( ) . span_delayed_bug ( span, "could not normalize field type" ) ;
169- continue ;
170- } ;
171159
172- if !allowed_union_or_unsafe_field ( tcx, field_ty , typing_env, span) {
160+ if !allowed_union_or_unsafe_field ( tcx, field . ty ( tcx , args ) , typing_env, span) {
173161 let hir:: Node :: Field ( field) = tcx. hir_node_by_def_id ( field. did . expect_local ( ) ) else {
174162 unreachable ! ( "field has to correspond to hir field" )
175163 } ;
0 commit comments