diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index df3368bdd30ae..8b3870e5cc605 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1166,10 +1166,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { fn check_backward_incompatible_drop( &mut self, location: Location, - place_span: (Place<'tcx>, Span), + (place, place_span): (Place<'tcx>, Span), state: &BorrowckDomain, ) { - let sd = AccessDepth::Drop; + let tcx = self.infcx.tcx; + // If this type does not need `Drop`, then treat it like a `StorageDead`. + // This is needed because we track the borrows of refs to thread locals, + // and we'll ICE because we don't track borrows behind shared references. + let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) { + AccessDepth::Drop + } else { + AccessDepth::Shallow(None) + }; let borrows_in_scope = self.borrows_in_scope(location, state); @@ -1179,7 +1187,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self, self.infcx.tcx, self.body, - (sd, place_span.0), + (sd, place), self.borrow_set, |borrow_index| borrows_in_scope.contains(borrow_index), |this, _borrow_index, borrow| { @@ -1190,7 +1198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { this.infcx.tcx.emit_node_span_lint( TAIL_EXPR_DROP_ORDER, CRATE_HIR_ID, - place_span.1, + place_span, session_diagnostics::TailExprDropOrder { borrowed }, ); // We may stop at the first case diff --git a/tests/ui/drop/tail_expr_drop_order-on-thread-local.rs b/tests/ui/drop/tail_expr_drop_order-on-thread-local.rs new file mode 100644 index 0000000000000..e38175fd1b653 --- /dev/null +++ b/tests/ui/drop/tail_expr_drop_order-on-thread-local.rs @@ -0,0 +1,56 @@ +//@ check-pass + +#![feature(thread_local)] +#![deny(tail_expr_drop_order)] + +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +pub struct Global; + +#[thread_local] +static REENTRANCY_STATE: State = State { marker: PhantomData, controller: Global }; + +pub struct Token(PhantomData<*mut ()>); + +pub fn with_mut(f: impl FnOnce(&mut Token) -> T) -> T { + f(&mut REENTRANCY_STATE.borrow_mut()) +} + +pub struct State { + marker: PhantomData<*mut ()>, + controller: T, +} + +impl State { + pub fn borrow_mut(&self) -> TokenMut<'_, T> { + todo!() + } +} + +pub struct TokenMut<'a, T: ?Sized = Global> { + state: &'a State, + token: Token, +} + +impl Deref for TokenMut<'_, T> { + type Target = Token; + + fn deref(&self) -> &Self::Target { + todo!() + } +} + +impl DerefMut for TokenMut<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + todo!() + } +} + +impl Drop for TokenMut<'_, T> { + fn drop(&mut self) { + todo!() + } +} + +fn main() {}