rustc_const_eval/util/
caller_location.rs

1use rustc_hir::LangItem;
2use rustc_middle::ty::layout::LayoutOf;
3use rustc_middle::ty::{self, TyCtxt};
4use rustc_middle::{bug, mir};
5use rustc_span::Symbol;
6use tracing::trace;
7
8use crate::const_eval::{CanAccessMutGlobal, CompileTimeInterpCx, mk_eval_cx_to_read_const_val};
9use crate::interpret::*;
10
11/// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
12fn alloc_caller_location<'tcx>(
13    ecx: &mut CompileTimeInterpCx<'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_dedup(filename.as_str()).unwrap()
23    } else {
24        ecx.allocate_str_dedup("<redacted>").unwrap()
25    };
26    let file = file.map_provenance(CtfeProvenance::as_immutable);
27    let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
28    let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
29
30    // Allocate memory for `CallerLocation` struct.
31    let loc_ty = ecx
32        .tcx
33        .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, None))
34        .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()]));
35    let loc_layout = ecx.layout_of(loc_ty).unwrap();
36    let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
37
38    // Initialize fields.
39    ecx.write_immediate(file.to_ref(ecx), &ecx.project_field(&location, 0).unwrap())
40        .expect("writing to memory we just allocated cannot fail");
41    ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap())
42        .expect("writing to memory we just allocated cannot fail");
43    ecx.write_scalar(col, &ecx.project_field(&location, 2).unwrap())
44        .expect("writing to memory we just allocated cannot fail");
45
46    location
47}
48
49pub(crate) fn const_caller_location_provider(
50    tcx: TyCtxt<'_>,
51    file: Symbol,
52    line: u32,
53    col: u32,
54) -> mir::ConstValue<'_> {
55    trace!("const_caller_location: {}:{}:{}", file, line, col);
56    let mut ecx = mk_eval_cx_to_read_const_val(
57        tcx,
58        rustc_span::DUMMY_SP, // FIXME: use a proper span here?
59        ty::TypingEnv::fully_monomorphized(),
60        CanAccessMutGlobal::No,
61    );
62
63    let loc_place = alloc_caller_location(&mut ecx, file, line, col);
64    if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
65        bug!("intern_const_alloc_recursive should not error in this case")
66    }
67    mir::ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr(), &tcx))
68}