|
3 | 3 | //! The main entry point is the `step` method. |
4 | 4 |
|
5 | 5 | use std::iter; |
| 6 | +use std::ops::Deref; |
6 | 7 |
|
7 | 8 | use either::Either; |
8 | 9 | use rustc_abi::{FIRST_VARIANT, FieldIdx}; |
9 | 10 | use rustc_data_structures::fx::FxHashSet; |
10 | 11 | use rustc_index::IndexSlice; |
| 12 | +use rustc_middle::mir::interpret::{GlobalAlloc, Provenance, Scalar}; |
11 | 13 | use rustc_middle::ty::{self, Instance, Ty}; |
12 | 14 | use rustc_middle::{bug, mir, span_bug}; |
13 | 15 | use rustc_span::source_map::Spanned; |
@@ -217,9 +219,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |
217 | 219 | } |
218 | 220 |
|
219 | 221 | Ref(_, borrow_kind, place) => { |
| 222 | + let is_reborrow_of_ref = if let Some(local) = place.local_or_deref_local() |
| 223 | + && place.is_indirect() |
| 224 | + { |
| 225 | + self.layout_of_local(self.frame(), local, None)?.ty.is_ref() |
| 226 | + } else { |
| 227 | + false |
| 228 | + }; |
| 229 | + |
220 | 230 | let src = self.eval_place(place)?; |
221 | 231 | let place = self.force_allocation(&src)?; |
222 | 232 | let val = ImmTy::from_immediate(place.to_ref(self), dest.layout); |
| 233 | + |
| 234 | + // Check whether this forms a cycle involving a static reference. |
| 235 | + // Ensure the place is not a reborrow from a raw pointer, since we do not want to |
| 236 | + // forbid static reference cycles that go through raw pointers. |
| 237 | + if is_reborrow_of_ref |
| 238 | + && let Immediate::Scalar(Scalar::Ptr(ptr, _)) = val.deref() |
| 239 | + && let Some(alloc_id) = ptr.provenance.get_alloc_id() |
| 240 | + && let Some(GlobalAlloc::Static(def_id)) = |
| 241 | + self.tcx.try_get_global_alloc(alloc_id) |
| 242 | + { |
| 243 | + M::before_static_ref_eval(self.tcx, &self.machine, *ptr, def_id)?; |
| 244 | + } |
| 245 | + |
223 | 246 | // A fresh reference was created, make sure it gets retagged. |
224 | 247 | let val = M::retag_ptr_value( |
225 | 248 | self, |
|
0 commit comments