Skip to content
Open
25 changes: 21 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
bx.lifetime_end(tmp, size);
}
fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret);

// If the return value was retagged as it was stored,
// then we might be in a different basic block now.
// Update the cached block for `target` to point to this new
// block, where codegen will continue.
fx.cached_llbbs[target] = CachedLlbb::Some(bx.llbb());
}
MergingSucc::False
} else {
Expand Down Expand Up @@ -2186,19 +2192,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
llval: Bx::Value,
) {
use self::ReturnDest::*;

let retags_enabled = bx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some();
match dest {
Nothing => (),
Store(dst) => bx.store_arg(ret_abi, llval, dst),
Store(dst) => {
bx.store_arg(ret_abi, llval, dst);
if retags_enabled {
self.codegen_retag_place(bx, dst, false);
}
}
IndirectOperand(tmp, index) => {
let op = bx.load_operand(tmp);
let mut op = bx.load_operand(tmp);
tmp.storage_dead(bx);
if retags_enabled {
op = self.codegen_retag_operand(bx, op, false);
}
self.overwrite_local(index, LocalRef::Operand(op));
self.debug_introduce_local(bx, index);
}
DirectOperand(index) => {
// If there is a cast, we have to store and reload.
let op = if let PassMode::Cast { .. } = ret_abi.mode {
let mut op = if let PassMode::Cast { .. } = ret_abi.mode {
let tmp = PlaceRef::alloca(bx, ret_abi.layout);
tmp.storage_live(bx);
bx.store_arg(ret_abi, llval, tmp);
Expand All @@ -2208,6 +2222,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
};
if retags_enabled {
op = self.codegen_retag_operand(bx, op, false);
}
self.overwrite_local(index, LocalRef::Operand(op));
self.debug_introduce_local(bx, index);
}
Expand Down
29 changes: 28 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod locals;
pub mod naked_asm;
pub mod operand;
pub mod place;
mod retag;
mod rvalue;
mod statement;

Expand Down Expand Up @@ -425,7 +426,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
return vec![];
}

let args = mir
let mut args = mir
.args_iter()
.enumerate()
.map(|(arg_index, local)| {
Expand Down Expand Up @@ -562,6 +563,32 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
})
.collect::<Vec<_>>();
if bx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some() {
args = args
.iter()
.map(|arg| match arg {
&LocalRef::Place(place_ref) => {
fx.codegen_retag_place(bx, place_ref, true);
LocalRef::Place(place_ref)
}
&LocalRef::UnsizedPlace(place_ref) => {
let operand = bx.load_operand(place_ref);
let retagged = fx.codegen_retag_operand(bx, operand, true);
assert!(matches!(retagged.val, OperandValue::Pair(_, _)));
retagged.val.store(bx, place_ref);
LocalRef::UnsizedPlace(place_ref)
}
&LocalRef::Operand(operand_ref) => {
let retagged = fx.codegen_retag_operand(bx, operand_ref, true);
LocalRef::Operand(retagged)
}
LocalRef::PendingOperand => LocalRef::PendingOperand,
})
.collect::<Vec<_>>();
// If we branched during retagging, then we need to update the
// start block to the new location.
fx.cached_llbbs[mir::START_BLOCK] = CachedLlbb::Some(bx.llbb());
}

if fx.instance.def.requires_caller_location(bx.tcx()) {
let mir_args = if let Some(num_untupled) = num_untupled {
Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/retag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! Experimental support for emitting retags as function calls in generated code.

use rustc_middle::mir::{Rvalue, WithRetag};

use crate::mir::FunctionCx;
use crate::mir::operand::OperandRef;
use crate::mir::place::PlaceRef;
use crate::traits::BuilderMethods;

pub(crate) fn rvalue_needs_retag(rvalue: &Rvalue<'_>) -> bool {
// `Ref` has its own internal retagging
!matches!(rvalue, Rvalue::Ref(..)) && !matches!(rvalue, Rvalue::Use(.., WithRetag::No))
}

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
/// Retags the pointers within an [`OperandRef`].
pub(crate) fn codegen_retag_operand(
&mut self,
_bx: &mut Bx,
operand: OperandRef<'tcx, Bx::Value>,
_is_fn_entry: bool,
) -> OperandRef<'tcx, Bx::Value> {
operand
}

/// Retags the pointers within a [`PlaceRef`].
pub(crate) fn codegen_retag_place(
&mut self,
_bx: &mut Bx,
_place_ref: PlaceRef<'tcx, Bx::Value>,
_is_fn_entry: bool,
) {
}
}
7 changes: 6 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
Ty::new_ref(tcx, tcx.lifetimes.re_erased, ty, bk.to_mutbl_lossy())
};
self.codegen_place_to_pointer(bx, place, mk_ref)
let op = self.codegen_place_to_pointer(bx, place, mk_ref);
if self.cx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some() {
self.codegen_retag_operand(bx, op, false)
} else {
op
}
}

// Note: Exclusive reborrowing is always equal to a memcpy, as the types do not change.
Expand Down
25 changes: 22 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rustc_middle::{bug, span_bug, ty};
use tracing::instrument;

use super::{FunctionCx, LocalRef};
use crate::mir::retag;
use crate::traits::*;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Expand All @@ -12,9 +13,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.set_debug_loc(bx, statement.source_info);
match statement.kind {
mir::StatementKind::Assign((ref place, ref rvalue)) => {
let needs_retag = bx.tcx().sess.opts.unstable_opts.codegen_emit_retag.is_some()
&& retag::rvalue_needs_retag(rvalue);

if let Some(index) = place.as_local() {
match self.locals[index] {
LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue),
LocalRef::Place(cg_dest) => {
self.codegen_rvalue(bx, cg_dest, rvalue);
if needs_retag {
self.codegen_retag_place(bx, cg_dest, false);
}
}
LocalRef::UnsizedPlace(cg_indirect_dest) => {
let ty = cg_indirect_dest.layout.ty;
span_bug!(
Expand All @@ -24,7 +33,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
);
}
LocalRef::PendingOperand => {
let operand = self.codegen_rvalue_operand(bx, rvalue);
let mut operand = self.codegen_rvalue_operand(bx, rvalue);
if needs_retag {
operand = self.codegen_retag_operand(bx, operand, false);
}
self.overwrite_local(index, LocalRef::Operand(operand));
self.debug_introduce_local(bx, index);
}
Expand All @@ -39,12 +51,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

// If the type is zero-sized, it's already been set here,
// but we still need to make sure we codegen the operand
self.codegen_rvalue_operand(bx, rvalue);
// and emit a retag.
let operand = self.codegen_rvalue_operand(bx, rvalue);
if needs_retag {
self.codegen_retag_operand(bx, operand, false);
}
}
}
} else {
let cg_dest = self.codegen_place(bx, place.as_ref());
self.codegen_rvalue(bx, cg_dest, rvalue);
if needs_retag {
self.codegen_retag_place(bx, cg_dest, false);
}
}
}
mir::StatementKind::SetDiscriminant { ref place, variant_index } => {
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use rustc_errors::ColorConfig;
use rustc_errors::emitter::HumanReadableErrorType;
use rustc_hir::attrs::{CollapseMacroDebuginfo, NativeLibKind};
use rustc_session::config::{
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CoverageLevel, CoverageOptions,
DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
FmtDebug, FunctionReturn, IncrementalStateAssertion, InliningThreshold, Input,
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, Cfg, CodegenRetagOptions, CoverageLevel,
CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation,
Externs, FmtDebug, FunctionReturn, IncrementalStateAssertion, InliningThreshold, Input,
InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli,
MirIncludeSpans, NextSolverConfig, Offload, Options, OutFileName, OutputType, OutputTypes,
PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip,
Expand Down Expand Up @@ -772,6 +772,7 @@ fn test_unstable_options_tracking_hash() {
})
);
tracked!(codegen_backend, Some("abc".to_string()));
tracked!(codegen_emit_retag, Some(CodegenRetagOptions::default()));
tracked!(
coverage_options,
CoverageOptions {
Expand Down
23 changes: 17 additions & 6 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ pub enum Offload {
Test,
}

/// The different settings that the `-Z codegen-emit-retag` flag can have.
#[derive(Copy, Clone, Debug, Default, PartialEq, Hash, Encodable, Decodable)]
pub struct CodegenRetagOptions {
/// Track interior mutable data on the level of references, instead of on the byte level.
pub no_precise_im: bool,
/// Track `UnsafePinned` data on the level of references, instead of on the byte level.
pub no_precise_pin: bool,
}

/// The different settings that the `-Z autodiff` flag can have.
#[derive(Clone, PartialEq, Hash, Debug, Encodable, Decodable)]
pub enum AutoDiff {
Expand Down Expand Up @@ -3045,12 +3054,13 @@ pub(crate) mod dep_tracking {
};

use super::{
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CoverageOptions,
CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, OutFileName, OutputType,
OutputTypes, PatchableFunctionEntry, Polonius, ResolveDocLinks, SourceFileHashAlgorithm,
SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CodegenRetagOptions,
CoverageOptions, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug,
FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto,
LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel,
OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius, ResolveDocLinks,
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
WasiExecModel,
};
use crate::lint;
use crate::utils::NativeLib;
Expand Down Expand Up @@ -3154,6 +3164,7 @@ pub(crate) mod dep_tracking {
InliningThreshold,
FunctionReturn,
Align,
CodegenRetagOptions
);

impl<T1, T2> DepTrackingHash for (T1, T2)
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,8 @@ mod desc {
pub(crate) const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
pub(crate) const parse_instrument_coverage: &str = parse_bool;
pub(crate) const parse_coverage_options: &str = "`block` | `branch` | `condition`";
pub(crate) const parse_codegen_retag_options: &str =
"either no value or a comma-separated list of settings: `no-precise-im`, `no-precise-pin`";
pub(crate) const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
pub(crate) const parse_unpretty: &str = "`string` or `string=string`";
pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
Expand Down Expand Up @@ -1523,6 +1525,29 @@ pub mod parse {
true
}

pub(crate) fn parse_codegen_retag_options(
slot: &mut Option<CodegenRetagOptions>,
v: Option<&str>,
) -> bool {
let mut no_precise_im = false;
let mut no_precise_pin = false;
if let Some(opt_list) = v.map(|s| s.split(',')) {
for opt in opt_list {
match opt {
"no-precise-im" => {
no_precise_im = true;
}
"no-precise-pin" => {
no_precise_pin = true;
}
_ => return false,
}
}
}
*slot = Some(CodegenRetagOptions { no_precise_im, no_precise_pin });
true
}

pub(crate) fn parse_coverage_options(slot: &mut CoverageOptions, v: Option<&str>) -> bool {
let Some(v) = v else { return true };

Expand Down Expand Up @@ -2242,6 +2267,8 @@ options! {
"hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
codegen_emit_retag: Option<CodegenRetagOptions> = (None, parse_codegen_retag_options, [TRACKED],
"emit retag function calls in generated code"),
codegen_source_order: bool = (false, parse_bool, [UNTRACKED],
"emit mono items in the order of spans in source files (default: no)"),
contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,8 @@ impl Session {
// HWAddressSanitizer and KernelHWAddressSanitizer will use lifetimes to detect use after
// scope bugs in the future.
|| self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
// Lifetimes are necessary for retagging semantics.
|| self.opts.unstable_opts.codegen_emit_retag.is_some()
}

pub fn diagnostic_width(&self) -> usize {
Expand Down
7 changes: 6 additions & 1 deletion src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,12 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
})
}
}
_ => unreachable!(),
_ => Err(UnresolvedPath {
item_id,
module_id,
partial_res: Some(Res::Def(DefKind::TyAlias, did)),
unresolved: variant_name.to_string().into(),
}),
}
}
_ => Err(UnresolvedPath {
Expand Down
11 changes: 11 additions & 0 deletions tests/rustdoc-ui/intra-doc/ty-alias-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![deny(rustdoc::broken_intra_doc_links)]
//~^ NOTE the lint level is defined here

/// [Self::a::b]
//~^ ERROR unresolved link to `Self::a::b`
//~| NOTE the struct `MyStruct` has no field or associated item named `a`
pub struct MyStruct;
/// [Self::a::b]
//~^ ERROR unresolved link to `Self::a::b`
//~| NOTE the type alias `MyAlias` has no associated item named `a`
pub type MyAlias = MyStruct;
20 changes: 20 additions & 0 deletions tests/rustdoc-ui/intra-doc/ty-alias-field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: unresolved link to `Self::a::b`
--> $DIR/ty-alias-field.rs:4:6
|
LL | /// [Self::a::b]
| ^^^^^^^^^^ the struct `MyStruct` has no field or associated item named `a`
|
note: the lint level is defined here
--> $DIR/ty-alias-field.rs:1:9
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: unresolved link to `Self::a::b`
--> $DIR/ty-alias-field.rs:8:6
|
LL | /// [Self::a::b]
| ^^^^^^^^^^ the type alias `MyAlias` has no associated item named `a`

error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/18611>.
fn add_state(op: <isize as HasState>::State) {
//~^ ERROR `isize: HasState` is not satisfied
//~| ERROR `isize: HasState` is not satisfied
Expand Down
Loading
Loading