Skip to content

Commit 0399709

Browse files
committed
Auto merge of rust-lang#130847 - matthiaskrgr:rollup-f0n80bw, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#130735 (Simple validation for unsize coercion in MIR validation) - rust-lang#130781 (Fix up setting strip = true in Cargo.toml makes build scripts fail in…) - rust-lang#130811 (add link from random() helper fn to extensive DefaultRandomSource docs) - rust-lang#130819 (Add `must_use` attribute to `len_utf8` and `len_utf16`.) - rust-lang#130832 (fix some cfg logic around optimize_for_size and 16-bit targets) - rust-lang#130842 (Add tracking issue for io_error_inprogress) r? `@ghost` `@rustbot` modify labels: rollup
2 parents b511753 + e805182 commit 0399709

File tree

13 files changed

+145
-48
lines changed

13 files changed

+145
-48
lines changed

compiler/rustc_codegen_cranelift/src/unsize.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,22 @@ pub(crate) fn unsized_info<'tcx>(
3434
let old_info =
3535
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
3636
if data_a.principal_def_id() == data_b.principal_def_id() {
37-
// A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
37+
// Codegen takes advantage of the additional assumption, where if the
38+
// principal trait def id of what's being casted doesn't change,
39+
// then we don't need to adjust the vtable at all. This
40+
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
41+
// requires that `A = B`; we don't allow *upcasting* objects
42+
// between the same trait with different args. If we, for
43+
// some reason, were to relax the `Unsize` trait, it could become
44+
// unsound, so let's assert here that the trait refs are *equal*.
45+
//
46+
// We can use `assert_eq` because the binders should have been anonymized,
47+
// and because higher-ranked equality now requires the binders are equal.
48+
debug_assert_eq!(
49+
data_a.principal(),
50+
data_b.principal(),
51+
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
52+
);
3853
return old_info;
3954
}
4055

compiler/rustc_codegen_ssa/src/back/link.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1087,16 +1087,17 @@ fn link_natively(
10871087
let strip = sess.opts.cg.strip;
10881088

10891089
if sess.target.is_like_osx {
1090+
let stripcmd = "/usr/bin/strip";
10901091
match (strip, crate_type) {
10911092
(Strip::Debuginfo, _) => {
1092-
strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-S"))
1093+
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S"))
10931094
}
10941095
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
10951096
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
1096-
strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-x"))
1097+
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x"))
10971098
}
10981099
(Strip::Symbols, _) => {
1099-
strip_symbols_with_external_utility(sess, "strip", out_filename, None)
1100+
strip_symbols_with_external_utility(sess, stripcmd, out_filename, None)
11001101
}
11011102
(Strip::None, _) => {}
11021103
}

compiler/rustc_codegen_ssa/src/base.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,28 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
125125
let old_info =
126126
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
127127
if data_a.principal_def_id() == data_b.principal_def_id() {
128-
// A NOP cast that doesn't actually change anything, should be allowed even with
129-
// invalid vtables.
128+
// Codegen takes advantage of the additional assumption, where if the
129+
// principal trait def id of what's being casted doesn't change,
130+
// then we don't need to adjust the vtable at all. This
131+
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
132+
// requires that `A = B`; we don't allow *upcasting* objects
133+
// between the same trait with different args. If we, for
134+
// some reason, were to relax the `Unsize` trait, it could become
135+
// unsound, so let's assert here that the trait refs are *equal*.
136+
//
137+
// We can use `assert_eq` because the binders should have been anonymized,
138+
// and because higher-ranked equality now requires the binders are equal.
139+
debug_assert_eq!(
140+
data_a.principal(),
141+
data_b.principal(),
142+
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
143+
);
144+
145+
// A NOP cast that doesn't actually change anything, let's avoid any
146+
// unnecessary work. This relies on the assumption that if the principal
147+
// traits are equal, then the associated type bounds (`dyn Trait<Assoc=T>`)
148+
// are also equal, which is ensured by the fact that normalization is
149+
// a function and we do not allow overlapping impls.
130150
return old_info;
131151
}
132152

compiler/rustc_mir_transform/src/validate.rs

+32-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
44
use rustc_hir::LangItem;
55
use rustc_index::IndexVec;
66
use rustc_index::bit_set::BitSet;
7-
use rustc_infer::traits::Reveal;
7+
use rustc_infer::infer::TyCtxtInferExt;
8+
use rustc_infer::traits::{Obligation, ObligationCause, Reveal};
89
use rustc_middle::mir::coverage::CoverageKind;
910
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
1011
use rustc_middle::mir::*;
@@ -16,6 +17,8 @@ use rustc_middle::ty::{
1617
use rustc_middle::{bug, span_bug};
1718
use rustc_target::abi::{FIRST_VARIANT, Size};
1819
use rustc_target::spec::abi::Abi;
20+
use rustc_trait_selection::traits::ObligationCtxt;
21+
use rustc_type_ir::Upcast;
1922

2023
use crate::util::{is_within_packed, relate_types};
2124

@@ -586,6 +589,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
586589

587590
crate::util::relate_types(self.tcx, self.param_env, variance, src, dest)
588591
}
592+
593+
/// Check that the given predicate definitely holds in the param-env of this MIR body.
594+
fn predicate_must_hold_modulo_regions(
595+
&self,
596+
pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
597+
) -> bool {
598+
let infcx = self.tcx.infer_ctxt().build();
599+
let ocx = ObligationCtxt::new(&infcx);
600+
ocx.register_obligation(Obligation::new(
601+
self.tcx,
602+
ObligationCause::dummy(),
603+
self.param_env,
604+
pred,
605+
));
606+
ocx.select_all_or_error().is_empty()
607+
}
589608
}
590609

591610
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
@@ -1202,8 +1221,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12021221
}
12031222
}
12041223
CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
1205-
// This is used for all `CoerceUnsized` types,
1206-
// not just pointers/references, so is hard to check.
1224+
// Pointers being unsize coerced should at least implement
1225+
// `CoerceUnsized`.
1226+
if !self.predicate_must_hold_modulo_regions(ty::TraitRef::new(
1227+
self.tcx,
1228+
self.tcx.require_lang_item(
1229+
LangItem::CoerceUnsized,
1230+
Some(self.body.source_info(location).span),
1231+
),
1232+
[op_ty, *target_type],
1233+
)) {
1234+
self.fail(location, format!("Unsize coercion, but `{op_ty}` isn't coercible to `{target_type}`"));
1235+
}
12071236
}
12081237
CastKind::PointerCoercion(PointerCoercion::DynStar, _) => {
12091238
// FIXME(dyn-star): make sure nothing needs to be done here.

library/core/src/char/methods.rs

+4
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ impl char {
606606
#[stable(feature = "rust1", since = "1.0.0")]
607607
#[rustc_const_stable(feature = "const_char_len_utf", since = "1.52.0")]
608608
#[inline]
609+
#[must_use]
609610
pub const fn len_utf8(self) -> usize {
610611
len_utf8(self as u32)
611612
}
@@ -637,6 +638,7 @@ impl char {
637638
#[stable(feature = "rust1", since = "1.0.0")]
638639
#[rustc_const_stable(feature = "const_char_len_utf", since = "1.52.0")]
639640
#[inline]
641+
#[must_use]
640642
pub const fn len_utf16(self) -> usize {
641643
len_utf16(self as u32)
642644
}
@@ -1738,6 +1740,7 @@ impl EscapeDebugExtArgs {
17381740
}
17391741

17401742
#[inline]
1743+
#[must_use]
17411744
const fn len_utf8(code: u32) -> usize {
17421745
match code {
17431746
..MAX_ONE_B => 1,
@@ -1748,6 +1751,7 @@ const fn len_utf8(code: u32) -> usize {
17481751
}
17491752

17501753
#[inline]
1754+
#[must_use]
17511755
const fn len_utf16(code: u32) -> usize {
17521756
if (code & 0xFFFF) == code { 1 } else { 2 }
17531757
}

library/core/src/slice/sort/shared/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![cfg_attr(feature = "optimize_for_size", allow(dead_code))]
1+
#![cfg_attr(any(feature = "optimize_for_size", target_pointer_width = "16"), allow(dead_code))]
22

33
use crate::marker::Freeze;
44

library/core/src/slice/sort/stable/mod.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
//! This module contains the entry points for `slice::sort`.
22
3-
#[cfg(not(feature = "optimize_for_size"))]
3+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
44
use crate::cmp;
55
use crate::intrinsics;
66
use crate::mem::{self, MaybeUninit, SizedTypeProperties};
7-
#[cfg(not(feature = "optimize_for_size"))]
7+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
88
use crate::slice::sort::shared::smallsort::{
99
SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left,
1010
};
1111

1212
pub(crate) mod merge;
1313

14-
#[cfg(not(feature = "optimize_for_size"))]
14+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
1515
pub(crate) mod drift;
16-
#[cfg(not(feature = "optimize_for_size"))]
16+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
1717
pub(crate) mod quicksort;
1818

19-
#[cfg(feature = "optimize_for_size")]
19+
#[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))]
2020
pub(crate) mod tiny;
2121

2222
/// Stable sort called driftsort by Orson Peters and Lukas Bergdoll.
@@ -45,7 +45,7 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less
4545

4646
cfg_if! {
4747
if #[cfg(target_pointer_width = "16")] {
48-
let heap_buf = BufT::with_capacity(alloc_len);
48+
let mut heap_buf = BufT::with_capacity(alloc_len);
4949
let scratch = heap_buf.as_uninit_slice_mut();
5050
} else {
5151
// For small inputs 4KiB of stack storage suffices, which allows us to avoid
@@ -85,7 +85,7 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less
8585
///
8686
/// Deliberately don't inline the main sorting routine entrypoint to ensure the
8787
/// inlined insertion sort i-cache footprint remains minimal.
88-
#[cfg(not(feature = "optimize_for_size"))]
88+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
8989
#[inline(never)]
9090
fn driftsort_main<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less: &mut F) {
9191
// By allocating n elements of memory we can ensure the entire input can

library/core/src/slice/sort/unstable/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
33
use crate::intrinsics;
44
use crate::mem::SizedTypeProperties;
5-
#[cfg(not(feature = "optimize_for_size"))]
5+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
66
use crate::slice::sort::shared::find_existing_run;
7-
#[cfg(not(feature = "optimize_for_size"))]
7+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
88
use crate::slice::sort::shared::smallsort::insertion_sort_shift_left;
99

1010
pub(crate) mod heapsort;
@@ -55,7 +55,7 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) {
5555
///
5656
/// Deliberately don't inline the main sorting routine entrypoint to ensure the
5757
/// inlined insertion sort i-cache footprint remains minimal.
58-
#[cfg(not(feature = "optimize_for_size"))]
58+
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
5959
#[inline(never)]
6060
fn ipnsort<T, F>(v: &mut [T], is_less: &mut F)
6161
where

library/std/src/io/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ pub enum ErrorKind {
402402

403403
/// The operation was partially successful and needs to be checked
404404
/// later on due to not blocking.
405-
#[unstable(feature = "io_error_inprogress", issue = "none")]
405+
#[unstable(feature = "io_error_inprogress", issue = "130840")]
406406
InProgress,
407407

408408
// "Unusual" error kinds which do not correspond simply to (sets

library/std/src/random.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ impl RandomSource for DefaultRandomSource {
7171
///
7272
/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and
7373
/// will sample according to the same distribution as the underlying [`Random`]
74-
/// trait implementation.
74+
/// trait implementation. See [`DefaultRandomSource`] for more information about
75+
/// how randomness is sourced.
7576
///
7677
/// **Warning:** Be careful when manipulating random values! The
7778
/// [`random`](Random::random) method on integers samples them with a uniform

tests/crashes/129219.rs

-26
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+Inline,+GVN -Zvalidate-mir
2+
3+
#![feature(unsize)]
4+
5+
use std::marker::Unsize;
6+
7+
pub trait CastTo<U: ?Sized>: Unsize<U> {}
8+
9+
// Not well-formed!
10+
impl<T: ?Sized, U: ?Sized> CastTo<U> for T {}
11+
//~^ ERROR the trait bound `T: Unsize<U>` is not satisfied
12+
13+
pub trait Cast {
14+
fn cast<U: ?Sized>(&self)
15+
where
16+
Self: CastTo<U>;
17+
}
18+
impl<T: ?Sized> Cast for T {
19+
#[inline(always)]
20+
fn cast<U: ?Sized>(&self)
21+
where
22+
Self: CastTo<U>,
23+
{
24+
let x: &U = self;
25+
}
26+
}
27+
28+
fn main() {
29+
// When we inline this call, then we run GVN, then
30+
// GVN tries to evaluate the `() -> [i32]` unsize.
31+
// That's invalid!
32+
().cast::<[i32]>();
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0277]: the trait bound `T: Unsize<U>` is not satisfied
2+
--> $DIR/validate-unsize-cast.rs:10:42
3+
|
4+
LL | impl<T: ?Sized, U: ?Sized> CastTo<U> for T {}
5+
| ^ the trait `Unsize<U>` is not implemented for `T`
6+
|
7+
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
8+
note: required by a bound in `CastTo`
9+
--> $DIR/validate-unsize-cast.rs:7:30
10+
|
11+
LL | pub trait CastTo<U: ?Sized>: Unsize<U> {}
12+
| ^^^^^^^^^ required by this bound in `CastTo`
13+
help: consider further restricting this bound
14+
|
15+
LL | impl<T: ?Sized + std::marker::Unsize<U>, U: ?Sized> CastTo<U> for T {}
16+
| ++++++++++++++++++++++++
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)