@@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
6
6
use rustc_errors:: MultiSpan ;
7
7
use rustc_errors:: codes:: * ;
8
8
use rustc_hir:: def:: { CtorKind , DefKind } ;
9
- use rustc_hir:: { Node , intravisit} ;
9
+ use rustc_hir:: { LangItem , Node , intravisit} ;
10
10
use rustc_infer:: infer:: { RegionVariableOrigin , TyCtxtInferExt } ;
11
11
use rustc_infer:: traits:: { Obligation , ObligationCauseCode } ;
12
12
use rustc_lint_defs:: builtin:: {
@@ -27,6 +27,7 @@ use rustc_session::lint::builtin::UNINHABITED_STATIC;
27
27
use rustc_trait_selection:: error_reporting:: InferCtxtErrorExt ;
28
28
use rustc_trait_selection:: error_reporting:: traits:: on_unimplemented:: OnUnimplementedDirective ;
29
29
use rustc_trait_selection:: traits;
30
+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
30
31
use rustc_type_ir:: fold:: TypeFoldable ;
31
32
use tracing:: { debug, instrument} ;
32
33
use ty:: TypingMode ;
@@ -87,89 +88,63 @@ fn allowed_union_or_unsafe_field<'tcx>(
87
88
typing_env : ty:: TypingEnv < ' tcx > ,
88
89
span : Span ,
89
90
) -> 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" ) ;
113
- }
114
- allowed
91
+ let ( infcx, param_env) = tcx. infer_ctxt ( ) . build_with_typing_env ( typing_env) ;
92
+ infcx. predicate_must_hold_modulo_regions ( & Obligation :: new (
93
+ tcx,
94
+ ObligationCause :: dummy_with_span ( span) ,
95
+ param_env,
96
+ ty:: TraitRef :: new (
97
+ tcx,
98
+ tcx. require_lang_item ( LangItem :: BikeshedGuaranteedNoDrop , Some ( span) ) ,
99
+ [ ty] ,
100
+ ) ,
101
+ ) )
115
102
}
116
103
117
104
/// Check that the fields of the `union` do not need dropping.
118
105
fn 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
- } ;
106
+ let def = tcx. adt_def ( item_def_id) ;
107
+ assert ! ( def. is_union( ) ) ;
130
108
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
- }
109
+ let typing_env = ty:: TypingEnv :: non_body_analysis ( tcx, item_def_id) ;
110
+ let args = ty:: GenericArgs :: identity_for_item ( tcx, item_def_id) ;
111
+
112
+ for field in & def. non_enum_variant ( ) . fields {
113
+ if !allowed_union_or_unsafe_field ( tcx, field. ty ( tcx, args) , typing_env, span) {
114
+ let ( field_span, ty_span) = match tcx. hir ( ) . get_if_local ( field. did ) {
115
+ // We are currently checking the type this field came from, so it must be local.
116
+ Some ( Node :: Field ( field) ) => ( field. span , field. ty . span ) ,
117
+ _ => unreachable ! ( "mir field has to correspond to hir field" ) ,
118
+ } ;
119
+ tcx. dcx ( ) . emit_err ( errors:: InvalidUnionField {
120
+ field_span,
121
+ sugg : errors:: InvalidUnionFieldSuggestion {
122
+ lo : ty_span. shrink_to_lo ( ) ,
123
+ hi : ty_span. shrink_to_hi ( ) ,
124
+ } ,
125
+ note : ( ) ,
126
+ } ) ;
127
+ return false ;
147
128
}
148
- } else {
149
- span_bug ! ( span, "unions must be ty::Adt, but got {:?}" , item_type. kind( ) ) ;
150
129
}
130
+
151
131
true
152
132
}
153
133
154
134
/// Check that the unsafe fields do not need dropping.
155
135
fn check_unsafe_fields ( tcx : TyCtxt < ' _ > , item_def_id : LocalDefId ) {
156
136
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
- } ;
137
+ let def = tcx. adt_def ( item_def_id) ;
138
+
161
139
let typing_env = ty:: TypingEnv :: non_body_analysis ( tcx, item_def_id) ;
140
+ let args = ty:: GenericArgs :: identity_for_item ( tcx, item_def_id) ;
141
+
162
142
for field in def. all_fields ( ) {
163
143
if !field. safety . is_unsafe ( ) {
164
144
continue ;
165
145
}
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
- } ;
171
146
172
- if !allowed_union_or_unsafe_field ( tcx, field_ty , typing_env, span) {
147
+ if !allowed_union_or_unsafe_field ( tcx, field . ty ( tcx , args ) , typing_env, span) {
173
148
let hir:: Node :: Field ( field) = tcx. hir_node_by_def_id ( field. did . expect_local ( ) ) else {
174
149
unreachable ! ( "field has to correspond to hir field" )
175
150
} ;
0 commit comments