Skip to main content

rustc_const_eval/util/
caller_location.rs

1use rustc_abi::FieldIdx;
2use rustc_hir::LangItem;
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    // Ensure that the filename itself does not contain nul bytes.
19    // This isn't possible via POSIX or Windows, but we should ensure no one
20    // ever does such a thing.
21    if !!filename.as_str().as_bytes().contains(&0) {
    ::core::panicking::panic("assertion failed: !filename.as_str().as_bytes().contains(&0)")
};assert!(!filename.as_str().as_bytes().contains(&0));
22
23    let loc_details = ecx.tcx.sess.opts.unstable_opts.location_detail;
24    let filename = {
25        let filename = if loc_details.file { filename.as_str() } else { "<redacted>" };
26        let filename_with_nul = filename.to_owned() + "\0";
27        // This can fail if rustc runs out of memory right here. Trying to emit an error would be
28        // pointless, since that would require allocating more memory than these short strings.
29        let file_ptr = ecx.allocate_bytes_dedup(filename_with_nul.as_bytes()).unwrap();
30        let file_len = u64::try_from(filename.len()).unwrap();
31        Immediate::new_slice(file_ptr.into(), file_len, ecx)
32    };
33    let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
34    let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
35
36    // Allocate memory for `CallerLocation` struct.
37    let loc_ty = ecx
38        .tcx
39        .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, ecx.tcx.span))
40        .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()]));
41    let loc_layout = ecx.layout_of(loc_ty).unwrap();
42    let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
43
44    // Initialize fields.
45    let [filename_field, line_field, col_field] =
46        ecx.project_fields(&location, [0, 1, 2].map(FieldIdx::from_u32)).unwrap();
47    ecx.write_immediate(filename, &filename_field)
48        .expect("writing to memory we just allocated cannot fail");
49    ecx.write_scalar(line, &line_field).expect("writing to memory we just allocated cannot fail");
50    ecx.write_scalar(col, &col_field).expect("writing to memory we just allocated cannot fail");
51
52    location
53}
54
55pub(crate) fn const_caller_location_provider(
56    tcx: TyCtxt<'_>,
57    file: Symbol,
58    line: u32,
59    col: u32,
60) -> mir::ConstValue {
61    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_const_eval/src/util/caller_location.rs:61",
                        "rustc_const_eval::util::caller_location",
                        ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/util/caller_location.rs"),
                        ::tracing_core::__macro_support::Option::Some(61u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::util::caller_location"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("const_caller_location: {0}:{1}:{2}",
                                                    file, line, col) as &dyn Value))])
            });
    } else { ; }
};trace!("const_caller_location: {}:{}:{}", file, line, col);
62    let mut ecx = mk_eval_cx_to_read_const_val(
63        tcx,
64        rustc_span::DUMMY_SP, // This interpreter cannot fail, so the span is irrelevant.
65        ty::TypingEnv::fully_monomorphized(),
66        CanAccessMutGlobal::No,
67    );
68
69    let loc_place = alloc_caller_location(&mut ecx, file, line, col);
70    if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
71        ::rustc_middle::util::bug::bug_fmt(format_args!("intern_const_alloc_recursive should not error in this case"))bug!("intern_const_alloc_recursive should not error in this case")
72    }
73    mir::ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr(), &tcx))
74}