|
| 1 | +use rustc_hir::LangItem; |
| 2 | +use rustc_middle::mir; |
| 3 | +use rustc_middle::ty::layout::LayoutOf; |
| 4 | +use rustc_middle::ty::{self, TyCtxt}; |
| 5 | +use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; |
| 6 | +use rustc_type_ir::Mutability; |
| 7 | + |
| 8 | +use crate::const_eval::{mk_eval_cx, CanAccessStatics, CompileTimeEvalContext}; |
| 9 | +use crate::interpret::*; |
| 10 | + |
| 11 | +/// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. |
| 12 | +fn alloc_caller_location<'mir, 'tcx>( |
| 13 | + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, |
| 14 | + filename: Symbol, |
| 15 | + line: u32, |
| 16 | + col: u32, |
| 17 | +) -> MPlaceTy<'tcx> { |
| 18 | + let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail; |
| 19 | + // This can fail if rustc runs out of memory right here. Trying to emit an error would be |
| 20 | + // pointless, since that would require allocating more memory than these short strings. |
| 21 | + let file = if loc_details.file { |
| 22 | + ecx.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not).unwrap() |
| 23 | + } else { |
| 24 | + // FIXME: This creates a new allocation each time. It might be preferable to |
| 25 | + // perform this allocation only once, and re-use the `MPlaceTy`. |
| 26 | + // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398 |
| 27 | + ecx.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap() |
| 28 | + }; |
| 29 | + let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; |
| 30 | + let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) }; |
| 31 | + |
| 32 | + // Allocate memory for `CallerLocation` struct. |
| 33 | + let loc_ty = ecx |
| 34 | + .tcx |
| 35 | + .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, None)) |
| 36 | + .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()])); |
| 37 | + let loc_layout = ecx.layout_of(loc_ty).unwrap(); |
| 38 | + let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); |
| 39 | + |
| 40 | + // Initialize fields. |
| 41 | + ecx.write_immediate(file.to_ref(ecx), &ecx.project_field(&location, 0).unwrap()) |
| 42 | + .expect("writing to memory we just allocated cannot fail"); |
| 43 | + ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap()) |
| 44 | + .expect("writing to memory we just allocated cannot fail"); |
| 45 | + ecx.write_scalar(col, &ecx.project_field(&location, 2).unwrap()) |
| 46 | + .expect("writing to memory we just allocated cannot fail"); |
| 47 | + |
| 48 | + location |
| 49 | +} |
| 50 | + |
| 51 | +pub(crate) fn const_caller_location_provider( |
| 52 | + tcx: TyCtxt<'_>, |
| 53 | + (file, line, col): (Symbol, u32, u32), |
| 54 | +) -> mir::ConstValue<'_> { |
| 55 | + trace!("const_caller_location: {}:{}:{}", file, line, col); |
| 56 | + let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), CanAccessStatics::No); |
| 57 | + |
| 58 | + let loc_place = alloc_caller_location(&mut ecx, file, line, col); |
| 59 | + if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { |
| 60 | + bug!("intern_const_alloc_recursive should not error in this case") |
| 61 | + } |
| 62 | + mir::ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr(), &tcx)) |
| 63 | +} |
0 commit comments