Skip to content

Commit bc145ce

Browse files
committed
Auto merge of #133950 - matthiaskrgr:rollup-b7g5p73, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #130777 (rust_for_linux: -Zreg-struct-return commandline flag for X86 (#116973)) - #133211 (Extend Miri to correctly pass mutable pointers through FFI) - #133790 (Improve documentation for Vec::extend_from_within) - #133930 (rustbook: update to use new mdbook-trpl package from The Book) - #133931 (Only allow PassMode::Direct for aggregates on wasm when using the C ABI) r? `@ghost` `@rustbot` modify labels: rollup
2 parents acf4842 + 875df6c commit bc145ce

File tree

40 files changed

+822
-114
lines changed

40 files changed

+822
-114
lines changed

compiler/rustc_codegen_gcc/src/context.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,10 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
544544

545545
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
546546
fn x86_abi_opt(&self) -> X86Abi {
547-
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
547+
X86Abi {
548+
regparm: self.tcx.sess.opts.unstable_opts.regparm,
549+
reg_struct_return: self.tcx.sess.opts.unstable_opts.reg_struct_return,
550+
}
548551
}
549552
}
550553

compiler/rustc_const_eval/src/const_eval/dummy_machine.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
168168
})
169169
}
170170

171-
fn expose_ptr(
172-
_ecx: &mut InterpCx<'tcx, Self>,
173-
_ptr: interpret::Pointer<Self::Provenance>,
171+
fn expose_provenance(
172+
_ecx: &InterpCx<'tcx, Self>,
173+
_provenance: Self::Provenance,
174174
) -> interpret::InterpResult<'tcx> {
175175
unimplemented!()
176176
}

compiler/rustc_const_eval/src/const_eval/machine.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ use crate::errors::{LongRunning, LongRunningWarn};
2121
use crate::fluent_generated as fluent;
2222
use crate::interpret::{
2323
self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy,
24-
InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, RangeSet, Scalar, compile_time_machine,
25-
interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup,
26-
throw_unsup_format,
24+
InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar, compile_time_machine, interp_ok,
25+
throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
2726
};
2827

2928
/// When hitting this many interpreted terminators we emit a deny by default lint
@@ -586,7 +585,10 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
586585
}
587586

588587
#[inline(always)]
589-
fn expose_ptr(_ecx: &mut InterpCx<'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> {
588+
fn expose_provenance(
589+
_ecx: &InterpCx<'tcx, Self>,
590+
_provenance: Self::Provenance,
591+
) -> InterpResult<'tcx> {
590592
// This is only reachable with -Zunleash-the-miri-inside-of-you.
591593
throw_unsup_format!("exposing pointers is not possible at compile-time")
592594
}

compiler/rustc_const_eval/src/interpret/cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
238238
let scalar = src.to_scalar();
239239
let ptr = scalar.to_pointer(self)?;
240240
match ptr.into_pointer_or_addr() {
241-
Ok(ptr) => M::expose_ptr(self, ptr)?,
241+
Ok(ptr) => M::expose_provenance(self, ptr.provenance)?,
242242
Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
243243
};
244244
interp_ok(ImmTy::from_scalar(

compiler/rustc_const_eval/src/interpret/machine.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,11 @@ pub trait Machine<'tcx>: Sized {
327327
addr: u64,
328328
) -> InterpResult<'tcx, Pointer<Option<Self::Provenance>>>;
329329

330-
/// Marks a pointer as exposed, allowing it's provenance
330+
/// Marks a pointer as exposed, allowing its provenance
331331
/// to be recovered. "Pointer-to-int cast"
332-
fn expose_ptr(
333-
ecx: &mut InterpCx<'tcx, Self>,
334-
ptr: Pointer<Self::Provenance>,
332+
fn expose_provenance(
333+
ecx: &InterpCx<'tcx, Self>,
334+
provenance: Self::Provenance,
335335
) -> InterpResult<'tcx>;
336336

337337
/// Convert a pointer with provenance into an allocation-offset pair and extra provenance info.

compiler/rustc_const_eval/src/interpret/memory.rs

+46
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
944944
interp_ok(())
945945
}
946946

947+
/// Handle the effect an FFI call might have on the state of allocations.
948+
/// This overapproximates the modifications which external code might make to memory:
949+
/// We set all reachable allocations as initialized, mark all provenances as exposed
950+
/// and overwrite them with `Provenance::WILDCARD`.
951+
pub fn prepare_for_native_call(
952+
&mut self,
953+
id: AllocId,
954+
initial_prov: M::Provenance,
955+
) -> InterpResult<'tcx> {
956+
// Expose provenance of the root allocation.
957+
M::expose_provenance(self, initial_prov)?;
958+
959+
let mut done = FxHashSet::default();
960+
let mut todo = vec![id];
961+
while let Some(id) = todo.pop() {
962+
if !done.insert(id) {
963+
// We already saw this allocation before, don't process it again.
964+
continue;
965+
}
966+
let info = self.get_alloc_info(id);
967+
968+
// If there is no data behind this pointer, skip this.
969+
if !matches!(info.kind, AllocKind::LiveData) {
970+
continue;
971+
}
972+
973+
// Expose all provenances in this allocation, and add them to `todo`.
974+
let alloc = self.get_alloc_raw(id)?;
975+
for prov in alloc.provenance().provenances() {
976+
M::expose_provenance(self, prov)?;
977+
if let Some(id) = prov.get_alloc_id() {
978+
todo.push(id);
979+
}
980+
}
981+
982+
// Prepare for possible write from native code if mutable.
983+
if info.mutbl.is_mut() {
984+
self.get_alloc_raw_mut(id)?
985+
.0
986+
.prepare_for_native_write()
987+
.map_err(|e| e.to_interp_error(id))?;
988+
}
989+
}
990+
interp_ok(())
991+
}
992+
947993
/// Create a lazy debug printer that prints the given allocation and all allocations it points
948994
/// to, recursively.
949995
#[must_use]

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ fn test_unstable_options_tracking_hash() {
832832
tracked!(precise_enum_drop_elaboration, false);
833833
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
834834
tracked!(profiler_runtime, "abc".to_string());
835+
tracked!(reg_struct_return, true);
835836
tracked!(regparm, Some(3));
836837
tracked!(relax_elf_relocations, Some(true));
837838
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));

compiler/rustc_middle/src/mir/interpret/allocation.rs

+22
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,28 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
643643
Ok(())
644644
}
645645

646+
/// Initialize all previously uninitialized bytes in the entire allocation, and set
647+
/// provenance of everything to `Wildcard`. Before calling this, make sure all
648+
/// provenance in this allocation is exposed!
649+
pub fn prepare_for_native_write(&mut self) -> AllocResult {
650+
let full_range = AllocRange { start: Size::ZERO, size: Size::from_bytes(self.len()) };
651+
// Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be.
652+
for chunk in self.init_mask.range_as_init_chunks(full_range) {
653+
if !chunk.is_init() {
654+
let uninit_bytes = &mut self.bytes
655+
[chunk.range().start.bytes_usize()..chunk.range().end.bytes_usize()];
656+
uninit_bytes.fill(0);
657+
}
658+
}
659+
// Mark everything as initialized now.
660+
self.mark_init(full_range, true);
661+
662+
// Set provenance of all bytes to wildcard.
663+
self.provenance.write_wildcards(self.len());
664+
665+
Ok(())
666+
}
667+
646668
/// Remove all provenance in the given memory range.
647669
pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
648670
self.provenance.clear(range, cx)?;

compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs

+19
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,25 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
195195

196196
Ok(())
197197
}
198+
199+
/// Overwrites all provenance in the allocation with wildcard provenance.
200+
///
201+
/// Provided for usage in Miri and panics otherwise.
202+
pub fn write_wildcards(&mut self, alloc_size: usize) {
203+
assert!(
204+
Prov::OFFSET_IS_ADDR,
205+
"writing wildcard provenance is not supported when `OFFSET_IS_ADDR` is false"
206+
);
207+
let wildcard = Prov::WILDCARD.unwrap();
208+
209+
// Remove all pointer provenances, then write wildcards into the whole byte range.
210+
self.ptrs.clear();
211+
let last = Size::from_bytes(alloc_size);
212+
let bytes = self.bytes.get_or_insert_with(Box::default);
213+
for offset in Size::ZERO..last {
214+
bytes.insert(offset, wildcard);
215+
}
216+
}
198217
}
199218

200219
/// A partial, owned list of provenance to transfer into another allocation.

compiler/rustc_middle/src/mir/interpret/pointer.rs

+9
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
6666
/// pointer, and implement ptr-to-int transmutation by stripping provenance.
6767
const OFFSET_IS_ADDR: bool;
6868

69+
/// If wildcard provenance is implemented, contains the unique, general wildcard provenance variant.
70+
const WILDCARD: Option<Self>;
71+
6972
/// Determines how a pointer should be printed.
7073
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
7174

@@ -168,6 +171,9 @@ impl Provenance for CtfeProvenance {
168171
// so ptr-to-int casts are not possible (since we do not know the global physical offset).
169172
const OFFSET_IS_ADDR: bool = false;
170173

174+
// `CtfeProvenance` does not implement wildcard provenance.
175+
const WILDCARD: Option<Self> = None;
176+
171177
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172178
// Print AllocId.
173179
fmt::Debug::fmt(&ptr.provenance.alloc_id(), f)?; // propagates `alternate` flag
@@ -197,6 +203,9 @@ impl Provenance for AllocId {
197203
// so ptr-to-int casts are not possible (since we do not know the global physical offset).
198204
const OFFSET_IS_ADDR: bool = false;
199205

206+
// `AllocId` does not implement wildcard provenance.
207+
const WILDCARD: Option<Self> = None;
208+
200209
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201210
// Forward `alternate` flag to `alloc_id` printing.
202211
if f.alternate() {

compiler/rustc_middle/src/ty/layout.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,10 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
552552

553553
impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
554554
fn x86_abi_opt(&self) -> X86Abi {
555-
X86Abi { regparm: self.sess.opts.unstable_opts.regparm }
555+
X86Abi {
556+
regparm: self.sess.opts.unstable_opts.regparm,
557+
reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return,
558+
}
556559
}
557560
}
558561

compiler/rustc_session/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -135,5 +135,6 @@ session_unsupported_crate_type_for_target =
135135
136136
session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
137137
138+
session_unsupported_reg_struct_return_arch = `-Zreg-struct-return` is only supported on x86
138139
session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3)
139140
session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86

compiler/rustc_session/src/errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ pub(crate) struct UnsupportedRegparm {
489489
#[diag(session_unsupported_regparm_arch)]
490490
pub(crate) struct UnsupportedRegparmArch;
491491

492+
#[derive(Diagnostic)]
493+
#[diag(session_unsupported_reg_struct_return_arch)]
494+
pub(crate) struct UnsupportedRegStructReturnArch;
495+
492496
#[derive(Diagnostic)]
493497
#[diag(session_failed_to_create_profiler)]
494498
pub(crate) struct FailedToCreateProfiler {

compiler/rustc_session/src/options.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1988,6 +1988,9 @@ options! {
19881988
"enable queries of the dependency graph for regression testing (default: no)"),
19891989
randomize_layout: bool = (false, parse_bool, [TRACKED],
19901990
"randomize the layout of types (default: no)"),
1991+
reg_struct_return: bool = (false, parse_bool, [TRACKED],
1992+
"On x86-32 targets, it overrides the default ABI to return small structs in registers.
1993+
It is UNSOUND to link together crates that use different values for this flag!"),
19911994
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
19921995
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
19931996
in registers EAX, EDX, and ECX instead of on the stack for\

compiler/rustc_session/src/session.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
13051305
sess.dcx().emit_err(errors::UnsupportedRegparmArch);
13061306
}
13071307
}
1308+
if sess.opts.unstable_opts.reg_struct_return {
1309+
if sess.target.arch != "x86" {
1310+
sess.dcx().emit_err(errors::UnsupportedRegStructReturnArch);
1311+
}
1312+
}
13081313

13091314
// The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is
13101315
// kept as a `match` to force a change if new ones are added, even if we currently only support

compiler/rustc_target/src/callconv/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
661661
}
662662
_ => (x86::Flavor::General, None),
663663
};
664-
x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm });
664+
let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
665+
let opts = x86::X86Options { flavor, regparm, reg_struct_return };
666+
x86::compute_abi_info(cx, self, opts);
665667
}
666668
"x86_64" => match abi {
667669
spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),

compiler/rustc_target/src/callconv/x86.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub(crate) enum Flavor {
1414
pub(crate) struct X86Options {
1515
pub flavor: Flavor,
1616
pub regparm: Option<u32>,
17+
pub reg_struct_return: bool,
1718
}
1819

1920
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
@@ -31,7 +32,7 @@ where
3132
// https://www.angelcode.com/dev/callconv/callconv.html
3233
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
3334
let t = cx.target_spec();
34-
if t.abi_return_struct_as_int {
35+
if t.abi_return_struct_as_int || opts.reg_struct_return {
3536
// According to Clang, everyone but MSVC returns single-element
3637
// float aggregates directly in a floating-point register.
3738
if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) {

compiler/rustc_target/src/spec/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2117,6 +2117,8 @@ pub struct X86Abi {
21172117
/// On x86-32 targets, the regparm N causes the compiler to pass arguments
21182118
/// in registers EAX, EDX, and ECX instead of on the stack.
21192119
pub regparm: Option<u32>,
2120+
/// Override the default ABI to return small structs in registers
2121+
pub reg_struct_return: bool,
21202122
}
21212123

21222124
pub trait HasX86AbiOpt {

compiler/rustc_ty_utils/src/abi.rs

+20-10
Original file line numberDiff line numberDiff line change
@@ -473,20 +473,30 @@ fn fn_abi_sanity_check<'tcx>(
473473
// This really shouldn't happen even for sized aggregates, since
474474
// `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an
475475
// LLVM type. This means all sorts of Rust type details leak into the ABI.
476-
// However wasm sadly *does* currently use this mode so we have to allow it --
477-
// but we absolutely shouldn't let any more targets do that.
478-
// (Also see <https://github.com/rust-lang/rust/issues/115666>.)
476+
// However wasm sadly *does* currently use this mode for it's "C" ABI so we
477+
// have to allow it -- but we absolutely shouldn't let any more targets do
478+
// that. (Also see <https://github.com/rust-lang/rust/issues/115666>.)
479479
//
480480
// The unstable abi `PtxKernel` also uses Direct for now.
481481
// It needs to switch to something else before stabilization can happen.
482482
// (See issue: https://github.com/rust-lang/rust/issues/117271)
483-
assert!(
484-
matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64")
485-
|| matches!(spec_abi, ExternAbi::PtxKernel | ExternAbi::Unadjusted),
486-
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\
487-
Problematic type: {:#?}",
488-
arg.layout,
489-
);
483+
//
484+
// And finally the unadjusted ABI is ill specified and uses Direct for all
485+
// args, but unfortunately we need it for calling certain LLVM intrinsics.
486+
487+
match spec_abi {
488+
ExternAbi::Unadjusted => {}
489+
ExternAbi::PtxKernel => {}
490+
ExternAbi::C { unwind: _ }
491+
if matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64") => {}
492+
_ => {
493+
panic!(
494+
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\
495+
Problematic type: {:#?}",
496+
arg.layout,
497+
);
498+
}
499+
}
490500
}
491501
}
492502
}

library/alloc/src/vec/mod.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -3025,26 +3025,29 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
30253025
self.spec_extend(other.iter())
30263026
}
30273027

3028-
/// Copies elements from `src` range to the end of the vector.
3028+
/// Given a range `src`, clones a slice of elements in that range and appends it to the end.
3029+
///
3030+
/// `src` must be a range that can form a valid subslice of the `Vec`.
30293031
///
30303032
/// # Panics
30313033
///
3032-
/// Panics if the starting point is greater than the end point or if
3033-
/// the end point is greater than the length of the vector.
3034+
/// Panics if starting index is greater than the end index
3035+
/// or if the index is greater than the length of the vector.
30343036
///
30353037
/// # Examples
30363038
///
30373039
/// ```
3038-
/// let mut vec = vec![0, 1, 2, 3, 4];
3039-
///
3040-
/// vec.extend_from_within(2..);
3041-
/// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4]);
3040+
/// let mut characters = vec!['a', 'b', 'c', 'd', 'e'];
3041+
/// characters.extend_from_within(2..);
3042+
/// assert_eq!(characters, ['a', 'b', 'c', 'd', 'e', 'c', 'd', 'e']);
30423043
///
3043-
/// vec.extend_from_within(..2);
3044-
/// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1]);
3044+
/// let mut numbers = vec![0, 1, 2, 3, 4];
3045+
/// numbers.extend_from_within(..2);
3046+
/// assert_eq!(numbers, [0, 1, 2, 3, 4, 0, 1]);
30453047
///
3046-
/// vec.extend_from_within(4..8);
3047-
/// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]);
3048+
/// let mut strings = vec![String::from("hello"), String::from("world"), String::from("!")];
3049+
/// strings.extend_from_within(1..=2);
3050+
/// assert_eq!(strings, ["hello", "world", "!", "world", "!"]);
30483051
/// ```
30493052
#[cfg(not(no_global_oom_handling))]
30503053
#[stable(feature = "vec_extend_from_within", since = "1.53.0")]

src/doc/book

Submodule book updated 147 files

0 commit comments

Comments
 (0)