summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/lib.rs16
-rw-r--r--tests/ui/drop/tail_expr_drop_order-on-thread-local.rs56
2 files changed, 68 insertions, 4 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index a3911642ee6..a35dff99669 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 00000000000..e38175fd1b6
--- /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<Global> = State { marker: PhantomData, controller: Global };
+
+pub struct Token(PhantomData<*mut ()>);
+
+pub fn with_mut<T>(f: impl FnOnce(&mut Token) -> T) -> T {
+    f(&mut REENTRANCY_STATE.borrow_mut())
+}
+
+pub struct State<T: ?Sized = Global> {
+    marker: PhantomData<*mut ()>,
+    controller: T,
+}
+
+impl<T: ?Sized> State<T> {
+    pub fn borrow_mut(&self) -> TokenMut<'_, T> {
+        todo!()
+    }
+}
+
+pub struct TokenMut<'a, T: ?Sized = Global> {
+    state: &'a State<T>,
+    token: Token,
+}
+
+impl<T> Deref for TokenMut<'_, T> {
+    type Target = Token;
+
+    fn deref(&self) -> &Self::Target {
+        todo!()
+    }
+}
+
+impl<T> DerefMut for TokenMut<'_, T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        todo!()
+    }
+}
+
+impl<T: ?Sized> Drop for TokenMut<'_, T> {
+    fn drop(&mut self) {
+        todo!()
+    }
+}
+
+fn main() {}