@@ -181,6 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
181181 self . check_mut_borrowing_layout_constrained_field ( * place, context. is_mutating_use ( ) ) ;
182182 }
183183
184+ // Check for borrows to packed fields.
185+ // `is_disaligned` already traverses the place to consider all projections after the last
186+ // `Deref`, so this only needs to be called once at the top level.
184187 if context. is_borrow ( ) {
185188 if util:: is_disaligned ( self . tcx , self . body , self . param_env , * place) {
186189 self . require_unsafe (
@@ -190,99 +193,105 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
190193 }
191194 }
192195
193- for ( i, _elem) in place. projection . iter ( ) . enumerate ( ) {
194- let proj_base = & place. projection [ ..i] ;
195- if context. is_borrow ( ) {
196- if util:: is_disaligned ( self . tcx , self . body , self . param_env , * place) {
196+ // Some checks below need the extra metainfo of the local declaration.
197+ let decl = & self . body . local_decls [ place. local ] ;
198+
199+ // Check the base local: it might be an unsafe-to-access static. We only check derefs of the
200+ // temporary holding the static pointer to avoid duplicate errors
201+ // <https://github.com/rust-lang/rust/pull/78068#issuecomment-731753506>.
202+ if decl. internal && place. projection . first ( ) == Some ( & ProjectionElem :: Deref ) {
203+ // If the projection root is an artifical local that we introduced when
204+ // desugaring `static`, give a more specific error message
205+ // (avoid the general "raw pointer" clause below, that would only be confusing).
206+ if let Some ( box LocalInfo :: StaticRef { def_id, .. } ) = decl. local_info {
207+ if self . tcx . is_mutable_static ( def_id) {
197208 self . require_unsafe (
198- UnsafetyViolationKind :: BorrowPacked ,
199- UnsafetyViolationDetails :: BorrowOfPackedField ,
209+ UnsafetyViolationKind :: General ,
210+ UnsafetyViolationDetails :: UseOfMutableStatic ,
200211 ) ;
212+ return ;
213+ } else if self . tcx . is_foreign_item ( def_id) {
214+ self . require_unsafe (
215+ UnsafetyViolationKind :: General ,
216+ UnsafetyViolationDetails :: UseOfExternStatic ,
217+ ) ;
218+ return ;
201219 }
202220 }
203- let source_info = self . source_info ;
204- if let [ ] = proj_base {
205- let decl = & self . body . local_decls [ place. local ] ;
206- if decl. internal {
207- // If the projection root is an artifical local that we introduced when
208- // desugaring `static`, give a more specific error message
209- // (avoid the general "raw pointer" clause below, that would only be confusing).
210- if let Some ( box LocalInfo :: StaticRef { def_id, .. } ) = decl. local_info {
211- if self . tcx . is_mutable_static ( def_id) {
212- self . require_unsafe (
213- UnsafetyViolationKind :: General ,
214- UnsafetyViolationDetails :: UseOfMutableStatic ,
215- ) ;
216- return ;
217- } else if self . tcx . is_foreign_item ( def_id) {
218- self . require_unsafe (
219- UnsafetyViolationKind :: General ,
220- UnsafetyViolationDetails :: UseOfExternStatic ,
221- ) ;
222- return ;
223- }
224- } else {
225- // Internal locals are used in the `move_val_init` desugaring.
226- // We want to check unsafety against the source info of the
227- // desugaring, rather than the source info of the RHS.
228- self . source_info = self . body . local_decls [ place. local ] . source_info ;
229- }
221+ }
222+
223+ // Check for raw pointer `Deref`.
224+ for ( base, proj) in place. iter_projections ( ) {
225+ if proj == ProjectionElem :: Deref {
226+ let source_info = self . source_info ; // Backup source_info so we can restore it later.
227+ if base. projection . is_empty ( ) && decl. internal {
228+ // Internal locals are used in the `move_val_init` desugaring.
229+ // We want to check unsafety against the source info of the
230+ // desugaring, rather than the source info of the RHS.
231+ self . source_info = self . body . local_decls [ place. local ] . source_info ;
230232 }
233+ let base_ty = base. ty ( self . body , self . tcx ) . ty ;
234+ if base_ty. is_unsafe_ptr ( ) {
235+ self . require_unsafe (
236+ UnsafetyViolationKind :: GeneralAndConstFn ,
237+ UnsafetyViolationDetails :: DerefOfRawPointer ,
238+ )
239+ }
240+ self . source_info = source_info; // Restore backed-up source_info.
241+ }
242+ }
243+
244+ // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes
245+ // whether we *read* the union field or potentially *write* to it (if this place is being assigned to).
246+ let mut saw_deref = false ;
247+ for ( base, proj) in place. iter_projections ( ) . rev ( ) {
248+ if proj == ProjectionElem :: Deref {
249+ saw_deref = true ;
250+ continue ;
231251 }
232- let base_ty = Place :: ty_from ( place. local , proj_base, self . body , self . tcx ) . ty ;
233- match base_ty. kind ( ) {
234- ty:: RawPtr ( ..) => self . require_unsafe (
235- UnsafetyViolationKind :: GeneralAndConstFn ,
236- UnsafetyViolationDetails :: DerefOfRawPointer ,
237- ) ,
238- ty:: Adt ( adt, _) if adt. is_union ( ) => {
239- let assign_to_field = matches ! (
252+
253+ let base_ty = base. ty ( self . body , self . tcx ) . ty ;
254+ if base_ty. ty_adt_def ( ) . map_or ( false , |adt| adt. is_union ( ) ) {
255+ // If we did not hit a `Deref` yet and the overall place use is an assignment, the
256+ // rules are different.
257+ let assign_to_field = !saw_deref
258+ && matches ! (
240259 context,
241260 PlaceContext :: MutatingUse (
242261 MutatingUseContext :: Store
243262 | MutatingUseContext :: Drop
244263 | MutatingUseContext :: AsmOutput
245264 )
246265 ) ;
247- // If there is a `Deref` further along the projection chain, this is *not* an
248- // assignment to a union field. In that case the union field is just read to
249- // obtain the pointer/reference.
250- let assign_to_field = assign_to_field
251- && !place. projection [ i..]
252- . iter ( )
253- . any ( |elem| matches ! ( elem, ProjectionElem :: Deref ) ) ;
254- // If this is just an assignment, determine if the assigned type needs dropping.
255- if assign_to_field {
256- // We have to check the actual type of the assignment, as that determines if the
257- // old value is being dropped.
258- let assigned_ty = place. ty ( & self . body . local_decls , self . tcx ) . ty ;
259- // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
260- let manually_drop = assigned_ty
261- . ty_adt_def ( )
262- . map_or ( false , |adt_def| adt_def. is_manually_drop ( ) ) ;
263- let nodrop = manually_drop
264- || assigned_ty. is_copy_modulo_regions (
265- self . tcx . at ( self . source_info . span ) ,
266- self . param_env ,
267- ) ;
268- if !nodrop {
269- self . require_unsafe (
270- UnsafetyViolationKind :: GeneralAndConstFn ,
271- UnsafetyViolationDetails :: AssignToDroppingUnionField ,
272- ) ;
273- } else {
274- // write to non-drop union field, safe
275- }
276- } else {
266+ // If this is just an assignment, determine if the assigned type needs dropping.
267+ if assign_to_field {
268+ // We have to check the actual type of the assignment, as that determines if the
269+ // old value is being dropped.
270+ let assigned_ty = place. ty ( & self . body . local_decls , self . tcx ) . ty ;
271+ // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
272+ let manually_drop = assigned_ty
273+ . ty_adt_def ( )
274+ . map_or ( false , |adt_def| adt_def. is_manually_drop ( ) ) ;
275+ let nodrop = manually_drop
276+ || assigned_ty. is_copy_modulo_regions (
277+ self . tcx . at ( self . source_info . span ) ,
278+ self . param_env ,
279+ ) ;
280+ if !nodrop {
277281 self . require_unsafe (
278282 UnsafetyViolationKind :: GeneralAndConstFn ,
279- UnsafetyViolationDetails :: AccessToUnionField ,
280- )
283+ UnsafetyViolationDetails :: AssignToDroppingUnionField ,
284+ ) ;
285+ } else {
286+ // write to non-drop union field, safe
281287 }
288+ } else {
289+ self . require_unsafe (
290+ UnsafetyViolationKind :: GeneralAndConstFn ,
291+ UnsafetyViolationDetails :: AccessToUnionField ,
292+ )
282293 }
283- _ => { }
284294 }
285- self . source_info = source_info;
286295 }
287296 }
288297}
0 commit comments