Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

share some track_caller logic between interpret and codegen #117317

Merged
merged 2 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 5 additions & 41 deletions compiler/rustc_codegen_cranelift/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,47 +430,11 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
}
}

// Note: must be kept in sync with get_caller_location from cg_ssa
pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> {
let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| {
use rustc_session::RemapFileNameExt;
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo());
let const_loc = fx.tcx.const_caller_location((
rustc_span::symbol::Symbol::intern(
&caller.file.name.for_codegen(&fx.tcx.sess).to_string_lossy(),
),
caller.line as u32,
caller.col_display as u32 + 1,
));
crate::constant::codegen_const_value(fx, const_loc, fx.tcx.caller_location_ty())
};

// Walk up the `SourceScope`s, in case some of them are from MIR inlining.
// If so, the starting `source_info.span` is in the innermost inlined
// function, and will be replaced with outer callsite spans as long
// as the inlined functions were `#[track_caller]`.
loop {
let scope_data = &self.mir.source_scopes[source_info.scope];

if let Some((callee, callsite_span)) = scope_data.inlined {
// Stop inside the most nested non-`#[track_caller]` function,
// before ever reaching its caller (which is irrelevant).
if !callee.def.requires_caller_location(self.tcx) {
return span_to_caller_location(self, source_info.span);
}
source_info.span = callsite_span;
}

// Skip past all of the parents with `inlined: None`.
match scope_data.inlined_parent_scope {
Some(parent) => source_info.scope = parent,
None => break,
}
}

// No inlined `SourceScope`s, or all of them were `#[track_caller]`.
self.caller_location.unwrap_or_else(|| span_to_caller_location(self, source_info.span))
pub(crate) fn get_caller_location(&mut self, source_info: mir::SourceInfo) -> CValue<'tcx> {
self.mir.caller_location_span(source_info, self.caller_location, self.tcx, |span| {
let const_loc = self.tcx.span_as_caller_location(span);
crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty())
})
}

pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
Expand Down
43 changes: 4 additions & 39 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,47 +1449,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn get_caller_location(
&mut self,
bx: &mut Bx,
mut source_info: mir::SourceInfo,
source_info: mir::SourceInfo,
) -> OperandRef<'tcx, Bx::Value> {
let tcx = bx.tcx();

let mut span_to_caller_location = |span: Span| {
use rustc_session::RemapFileNameExt;
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
let const_loc = tcx.const_caller_location((
Symbol::intern(&caller.file.name.for_codegen(self.cx.sess()).to_string_lossy()),
caller.line as u32,
caller.col_display as u32 + 1,
));
self.mir.caller_location_span(source_info, self.caller_location, bx.tcx(), |span: Span| {
let const_loc = bx.tcx().span_as_caller_location(span);
OperandRef::from_const(bx, const_loc, bx.tcx().caller_location_ty())
};

// Walk up the `SourceScope`s, in case some of them are from MIR inlining.
// If so, the starting `source_info.span` is in the innermost inlined
// function, and will be replaced with outer callsite spans as long
// as the inlined functions were `#[track_caller]`.
loop {
let scope_data = &self.mir.source_scopes[source_info.scope];

if let Some((callee, callsite_span)) = scope_data.inlined {
// Stop inside the most nested non-`#[track_caller]` function,
// before ever reaching its caller (which is irrelevant).
if !callee.def.requires_caller_location(tcx) {
return span_to_caller_location(source_info.span);
}
source_info.span = callsite_span;
}

// Skip past all of the parents with `inlined: None`.
match scope_data.inlined_parent_scope {
Some(parent) => source_info.scope = parent,
None => break,
}
}

// No inlined `SourceScope`s, or all of them were `#[track_caller]`.
self.caller_location.unwrap_or_else(|| span_to_caller_location(source_info.span))
})
}

fn get_personality_slot(&mut self, bx: &mut Bx) -> PlaceRef<'tcx, Bx::Value> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
/// that inform us about the generic bounds of the constant. E.g., using an associated constant
/// of a function's generic parameter will require knowledge about the bounds on the generic
/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
pub(super) fn mk_eval_cx<'mir, 'tcx>(
pub(crate) fn mk_eval_cx<'mir, 'tcx>(
tcx: TyCtxt<'tcx>,
root_span: Span,
param_env: ty::ParamEnv<'tcx>,
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use rustc_middle::mir;
use rustc_middle::mir::interpret::PointerArithmetic;
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Span;
use std::borrow::Borrow;
use std::hash::Hash;
use std::ops::ControlFlow;
Expand Down Expand Up @@ -181,6 +182,24 @@ impl interpret::MayLeak for ! {
}

impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());

use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
(
Symbol::intern(
&caller
.file
.name
.for_scope(&self.tcx.sess, RemapPathScopeComponents::DIAGNOSTICS)
.to_string_lossy(),
),
u32::try_from(caller.line).unwrap(),
u32::try_from(caller.col_display).unwrap().checked_add(1).unwrap(),
)
}

/// "Intercept" a function call, because we have something special to do for it.
/// All `#[rustc_do_not_const_check]` functions should be hooked here.
/// If this returns `Some` function, which may be `instance` or a different function with
Expand Down
18 changes: 2 additions & 16 deletions compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Not in interpret to make sure we do not use private implementation details

use crate::errors::MaxNumNodesInConstErr;
use crate::interpret::{intern_const_alloc_recursive, InternKind, InterpCx, Scalar};
use crate::interpret::InterpCx;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
use rustc_span::source_map::DUMMY_SP;

mod error;
mod eval_queries;
Expand All @@ -20,20 +20,6 @@ pub use fn_queries::*;
pub use machine::*;
pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value};

pub(crate) fn const_caller_location(
tcx: TyCtxt<'_>,
(file, line, col): (Symbol, u32, u32),
) -> mir::ConstValue<'_> {
trace!("const_caller_location: {}:{}:{}", file, line, col);
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), CanAccessStatics::No);

let loc_place = ecx.alloc_caller_location(file, line, col);
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
bug!("intern_const_alloc_recursive should not error in this case")
}
mir::ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr(), &tcx))
}

// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
const VALTREE_MAX_NODES: usize = 100000;

Expand Down
44 changes: 44 additions & 0 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}

/// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
/// frame which is not `#[track_caller]`. This is the fancy version of `cur_span`.
pub(crate) fn find_closest_untracked_caller_location(&self) -> Span {
for frame in self.stack().iter().rev() {
debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance);

// Assert that the frame we look at is actually executing code currently
// (`loc` is `Right` when we are unwinding and the frame does not require cleanup).
let loc = frame.loc.left().unwrap();

// This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all
// (such as `box`). Use the normal span by default.
let mut source_info = *frame.body.source_info(loc);

// If this is a `Call` terminator, use the `fn_span` instead.
let block = &frame.body.basic_blocks[loc.block];
if loc.statement_index == block.statements.len() {
debug!(
"find_closest_untracked_caller_location: got terminator {:?} ({:?})",
block.terminator(),
block.terminator().kind,
);
if let mir::TerminatorKind::Call { fn_span, .. } = block.terminator().kind {
source_info.span = fn_span;
}
}

let caller_location = if frame.instance.def.requires_caller_location(*self.tcx) {
// We use `Err(())` as indication that we should continue up the call stack since
// this is a `#[track_caller]` function.
Some(Err(()))
} else {
None
};
if let Ok(span) =
frame.body.caller_location_span(source_info, caller_location, *self.tcx, Ok)
{
return span;
}
}

span_bug!(self.cur_span(), "no non-`#[track_caller]` frame found")
}

#[inline(always)]
pub fn layout_of_local(
&self,
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ use super::{

use crate::fluent_generated as fluent;

mod caller_location;

fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> {
let size = match kind {
Primitive::Int(integer, _) => integer.size(),
Expand Down Expand Up @@ -130,8 +128,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
match intrinsic_name {
sym::caller_location => {
let span = self.find_closest_untracked_caller_location();
let location = self.alloc_caller_location_for_span(span);
self.write_immediate(location.to_ref(self), dest)?;
let val = self.tcx.span_as_caller_location(span);
let val =
self.const_val_to_op(val, self.tcx.caller_location_ty(), Some(dest.layout))?;
self.copy_op(&val, dest, /* allow_transmute */ false)?;
}

sym::min_align_of_val | sym::size_of_val => {
Expand Down
136 changes: 0 additions & 136 deletions compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs

This file was deleted.

Loading
Loading