Skip to content

Commit 2d3a85b

Browse files
committedOct 7, 2022
Auto merge of rust-lang#102787 - Dylan-DPC:rollup-fvbb4t9, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - rust-lang#102300 (Use a macro to not have to copy-paste `ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp)).0` everywhere) - rust-lang#102475 (unsafe keyword: trait examples and unsafe_op_in_unsafe_fn update) - rust-lang#102760 (Avoid repeated re-initialization of the BufReader buffer) - rust-lang#102764 (Check `WhereClauseReferencesSelf` after all other object safety checks) - rust-lang#102779 (Fix `type_of` ICE) - rust-lang#102780 (run Miri CI when std::sys changes) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 43c22af + 3800d40 commit 2d3a85b

File tree

20 files changed

+319
-164
lines changed

20 files changed

+319
-164
lines changed
 

‎compiler/rustc_hir_analysis/src/collect/type_of.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,8 +493,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
493493
},
494494
def_id.to_def_id(),
495495
);
496-
if let Some(assoc_item) = assoc_item {
497-
tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id)
496+
if let Some(param)
497+
= assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
498+
{
499+
tcx.type_of(param.def_id)
498500
} else {
499501
// FIXME(associated_const_equality): add a useful error message here.
500502
tcx.ty_error_with_message(

‎compiler/rustc_trait_selection/src/traits/object_safety.rs‎

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -447,19 +447,6 @@ fn virtual_call_violation_for_method<'tcx>(
447447
return Some(MethodViolationCode::Generic);
448448
}
449449

450-
if tcx
451-
.predicates_of(method.def_id)
452-
.predicates
453-
.iter()
454-
// A trait object can't claim to live more than the concrete type,
455-
// so outlives predicates will always hold.
456-
.cloned()
457-
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
458-
.any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
459-
{
460-
return Some(MethodViolationCode::WhereClauseReferencesSelf);
461-
}
462-
463450
let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
464451

465452
// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
@@ -538,6 +525,21 @@ fn virtual_call_violation_for_method<'tcx>(
538525
}
539526
}
540527

528+
// NOTE: This check happens last, because it results in a lint, and not a
529+
// hard error.
530+
if tcx
531+
.predicates_of(method.def_id)
532+
.predicates
533+
.iter()
534+
// A trait object can't claim to live more than the concrete type,
535+
// so outlives predicates will always hold.
536+
.cloned()
537+
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
538+
.any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
539+
{
540+
return Some(MethodViolationCode::WhereClauseReferencesSelf);
541+
}
542+
541543
None
542544
}
543545

‎library/core/src/iter/adapters/array_chunks.rs‎

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::array;
2-
use crate::const_closure::ConstFnMutClosure;
32
use crate::iter::{ByRefSized, FusedIterator, Iterator};
4-
use crate::ops::{ControlFlow, NeverShortCircuit, Try};
3+
use crate::ops::{ControlFlow, Try};
54

65
/// An iterator over `N` elements of the iterator at a time.
76
///
@@ -83,13 +82,7 @@ where
8382
}
8483
}
8584

86-
fn fold<B, F>(mut self, init: B, mut f: F) -> B
87-
where
88-
Self: Sized,
89-
F: FnMut(B, Self::Item) -> B,
90-
{
91-
self.try_fold(init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp)).0
92-
}
85+
impl_fold_via_try_fold! { fold -> try_fold }
9386
}
9487

9588
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
@@ -127,13 +120,7 @@ where
127120
try { acc }
128121
}
129122

130-
fn rfold<B, F>(mut self, init: B, mut f: F) -> B
131-
where
132-
Self: Sized,
133-
F: FnMut(B, Self::Item) -> B,
134-
{
135-
self.try_rfold(init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp)).0
136-
}
123+
impl_fold_via_try_fold! { rfold -> try_rfold }
137124
}
138125

139126
impl<I, const N: usize> ArrayChunks<I, N>

‎library/core/src/iter/adapters/map_while.rs‎

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,7 @@ where
6464
.into_try()
6565
}
6666

67-
#[inline]
68-
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
69-
where
70-
Self: Sized,
71-
Fold: FnMut(Acc, Self::Item) -> Acc,
72-
{
73-
#[inline]
74-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
75-
move |acc, x| Ok(f(acc, x))
76-
}
77-
78-
self.try_fold(init, ok(fold)).unwrap()
79-
}
67+
impl_fold_via_try_fold! { fold -> try_fold }
8068
}
8169

8270
#[unstable(issue = "none", feature = "inplace_iteration")]

‎library/core/src/iter/adapters/mod.rs‎

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use crate::const_closure::ConstFnMutClosure;
21
use crate::iter::{InPlaceIterable, Iterator};
3-
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
2+
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
43

54
mod array_chunks;
65
mod by_ref_sized;
@@ -204,13 +203,7 @@ where
204203
.into_try()
205204
}
206205

207-
fn fold<B, F>(mut self, init: B, mut fold: F) -> B
208-
where
209-
Self: Sized,
210-
F: FnMut(B, Self::Item) -> B,
211-
{
212-
self.try_fold(init, ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp)).0
213-
}
206+
impl_fold_via_try_fold! { fold -> try_fold }
214207
}
215208

216209
#[unstable(issue = "none", feature = "inplace_iteration")]

‎library/core/src/iter/adapters/scan.rs‎

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,7 @@ where
7474
self.iter.try_fold(init, scan(state, f, fold)).into_try()
7575
}
7676

77-
#[inline]
78-
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
79-
where
80-
Self: Sized,
81-
Fold: FnMut(Acc, Self::Item) -> Acc,
82-
{
83-
#[inline]
84-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
85-
move |acc, x| Ok(f(acc, x))
86-
}
87-
88-
self.try_fold(init, ok(fold)).unwrap()
89-
}
77+
impl_fold_via_try_fold! { fold -> try_fold }
9078
}
9179

9280
#[unstable(issue = "none", feature = "inplace_iteration")]

‎library/core/src/iter/adapters/skip.rs‎

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,17 +206,7 @@ where
206206
if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
207207
}
208208

209-
fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
210-
where
211-
Fold: FnMut(Acc, Self::Item) -> Acc,
212-
{
213-
#[inline]
214-
fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
215-
move |acc, x| Ok(f(acc, x))
216-
}
217-
218-
self.try_rfold(init, ok(fold)).unwrap()
219-
}
209+
impl_fold_via_try_fold! { rfold -> try_rfold }
220210

221211
#[inline]
222212
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {

‎library/core/src/iter/adapters/take.rs‎

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,7 @@ where
9898
}
9999
}
100100

101-
#[inline]
102-
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
103-
where
104-
Self: Sized,
105-
Fold: FnMut(Acc, Self::Item) -> Acc,
106-
{
107-
#[inline]
108-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
109-
move |acc, x| Ok(f(acc, x))
110-
}
111-
112-
self.try_fold(init, ok(fold)).unwrap()
113-
}
101+
impl_fold_via_try_fold! { fold -> try_fold }
114102

115103
#[inline]
116104
#[rustc_inherit_overflow_checks]

‎library/core/src/iter/adapters/take_while.rs‎

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,7 @@ where
9494
}
9595
}
9696

97-
#[inline]
98-
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
99-
where
100-
Self: Sized,
101-
Fold: FnMut(Acc, Self::Item) -> Acc,
102-
{
103-
#[inline]
104-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
105-
move |acc, x| Ok(f(acc, x))
106-
}
107-
108-
self.try_fold(init, ok(fold)).unwrap()
109-
}
97+
impl_fold_via_try_fold! { fold -> try_fold }
11098
}
11199

112100
#[stable(feature = "fused", since = "1.26.0")]

‎library/core/src/iter/mod.rs‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,29 @@
352352
353353
#![stable(feature = "rust1", since = "1.0.0")]
354354

355+
// This needs to be up here in order to be usable in the child modules
356+
macro_rules! impl_fold_via_try_fold {
357+
(fold -> try_fold) => {
358+
impl_fold_via_try_fold! { @internal fold -> try_fold }
359+
};
360+
(rfold -> try_rfold) => {
361+
impl_fold_via_try_fold! { @internal rfold -> try_rfold }
362+
};
363+
(@internal $fold:ident -> $try_fold:ident) => {
364+
#[inline]
365+
fn $fold<AAA, FFF>(mut self, init: AAA, mut fold: FFF) -> AAA
366+
where
367+
FFF: FnMut(AAA, Self::Item) -> AAA,
368+
{
369+
use crate::const_closure::ConstFnMutClosure;
370+
use crate::ops::NeverShortCircuit;
371+
372+
let fold = ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp);
373+
self.$try_fold(init, fold).0
374+
}
375+
};
376+
}
377+
355378
#[stable(feature = "rust1", since = "1.0.0")]
356379
pub use self::traits::Iterator;
357380

‎library/core/src/iter/range.rs‎

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,19 +1150,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
11501150
self.spec_try_fold(init, f)
11511151
}
11521152

1153-
#[inline]
1154-
fn fold<B, F>(mut self, init: B, f: F) -> B
1155-
where
1156-
Self: Sized,
1157-
F: FnMut(B, Self::Item) -> B,
1158-
{
1159-
#[inline]
1160-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
1161-
move |acc, x| Ok(f(acc, x))
1162-
}
1163-
1164-
self.try_fold(init, ok(f)).unwrap()
1165-
}
1153+
impl_fold_via_try_fold! { fold -> try_fold }
11661154

11671155
#[inline]
11681156
fn last(mut self) -> Option<A> {
@@ -1230,19 +1218,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
12301218
self.spec_try_rfold(init, f)
12311219
}
12321220

1233-
#[inline]
1234-
fn rfold<B, F>(mut self, init: B, f: F) -> B
1235-
where
1236-
Self: Sized,
1237-
F: FnMut(B, Self::Item) -> B,
1238-
{
1239-
#[inline]
1240-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
1241-
move |acc, x| Ok(f(acc, x))
1242-
}
1243-
1244-
self.try_rfold(init, ok(f)).unwrap()
1245-
}
1221+
impl_fold_via_try_fold! { rfold -> try_rfold }
12461222
}
12471223

12481224
// Safety: See above implementation for `ops::Range<A>`

‎library/std/src/io/buffered/bufreader.rs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,14 @@ impl<R> BufReader<R> {
224224
}
225225
}
226226

227+
// This is only used by a test which asserts that the initialization-tracking is correct.
228+
#[cfg(test)]
229+
impl<R> BufReader<R> {
230+
pub fn initialized(&self) -> usize {
231+
self.buf.initialized()
232+
}
233+
}
234+
227235
impl<R: Seek> BufReader<R> {
228236
/// Seeks relative to the current position. If the new position lies within the buffer,
229237
/// the buffer will not be flushed, allowing for more efficient seeks.

‎library/std/src/io/buffered/bufreader/buffer.rs‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,19 @@ pub struct Buffer {
2020
// Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
2121
// initialized with bytes from a read.
2222
filled: usize,
23+
// This is the max number of bytes returned across all `fill_buf` calls. We track this so that we
24+
// can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its
25+
// defensive initialization as possible. Note that while this often the same as `filled`, it
26+
// doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and
27+
// omitting this is a huge perf regression for `Read` impls that do not.
28+
initialized: usize,
2329
}
2430

2531
impl Buffer {
2632
#[inline]
2733
pub fn with_capacity(capacity: usize) -> Self {
2834
let buf = Box::new_uninit_slice(capacity);
29-
Self { buf, pos: 0, filled: 0 }
35+
Self { buf, pos: 0, filled: 0, initialized: 0 }
3036
}
3137

3238
#[inline]
@@ -51,6 +57,12 @@ impl Buffer {
5157
self.pos
5258
}
5359

60+
// This is only used by a test which asserts that the initialization-tracking is correct.
61+
#[cfg(test)]
62+
pub fn initialized(&self) -> usize {
63+
self.initialized
64+
}
65+
5466
#[inline]
5567
pub fn discard_buffer(&mut self) {
5668
self.pos = 0;
@@ -96,13 +108,14 @@ impl Buffer {
96108
let mut buf = BorrowedBuf::from(&mut *self.buf);
97109
// SAFETY: `self.filled` bytes will always have been initialized.
98110
unsafe {
99-
buf.set_init(self.filled);
111+
buf.set_init(self.initialized);
100112
}
101113

102114
reader.read_buf(buf.unfilled())?;
103115

104-
self.filled = buf.len();
105116
self.pos = 0;
117+
self.filled = buf.len();
118+
self.initialized = buf.init_len();
106119
}
107120
Ok(self.buffer())
108121
}

‎library/std/src/io/buffered/tests.rs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,3 +1039,27 @@ fn single_formatted_write() {
10391039
writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap();
10401040
assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]);
10411041
}
1042+
1043+
#[test]
1044+
fn bufreader_full_initialize() {
1045+
struct OneByteReader;
1046+
impl Read for OneByteReader {
1047+
fn read(&mut self, buf: &mut [u8]) -> crate::io::Result<usize> {
1048+
if buf.len() > 0 {
1049+
buf[0] = 0;
1050+
Ok(1)
1051+
} else {
1052+
Ok(0)
1053+
}
1054+
}
1055+
}
1056+
let mut reader = BufReader::new(OneByteReader);
1057+
// Nothing is initialized yet.
1058+
assert_eq!(reader.initialized(), 0);
1059+
1060+
let buf = reader.fill_buf().unwrap();
1061+
// We read one byte...
1062+
assert_eq!(buf.len(), 1);
1063+
// But we initialized the whole buffer!
1064+
assert_eq!(reader.initialized(), reader.capacity());
1065+
}

‎library/std/src/keyword_docs.rs‎

Lines changed: 120 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,11 +1867,15 @@ mod type_keyword {}
18671867
/// Code or interfaces whose [memory safety] cannot be verified by the type
18681868
/// system.
18691869
///
1870-
/// The `unsafe` keyword has two uses: to declare the existence of contracts the
1871-
/// compiler can't check (`unsafe fn` and `unsafe trait`), and to declare that a
1872-
/// programmer has checked that these contracts have been upheld (`unsafe {}`
1873-
/// and `unsafe impl`, but also `unsafe fn` -- see below). They are not mutually
1874-
/// exclusive, as can be seen in `unsafe fn`.
1870+
/// The `unsafe` keyword has two uses:
1871+
/// - to declare the existence of contracts the compiler can't check (`unsafe fn` and `unsafe
1872+
/// trait`),
1873+
/// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe
1874+
/// {}` and `unsafe impl`, but also `unsafe fn` -- see below).
1875+
///
1876+
/// They are not mutually exclusive, as can be seen in `unsafe fn`: the body of an `unsafe fn` is,
1877+
/// by default, treated like an unsafe block. The `unsafe_op_in_unsafe_fn` lint can be enabled to
1878+
/// change that.
18751879
///
18761880
/// # Unsafe abilities
18771881
///
@@ -1914,12 +1918,12 @@ mod type_keyword {}
19141918
/// - `unsafe impl`: the contract necessary to implement the trait has been
19151919
/// checked by the programmer and is guaranteed to be respected.
19161920
///
1917-
/// `unsafe fn` also acts like an `unsafe {}` block
1921+
/// By default, `unsafe fn` also acts like an `unsafe {}` block
19181922
/// around the code inside the function. This means it is not just a signal to
19191923
/// the caller, but also promises that the preconditions for the operations
1920-
/// inside the function are upheld. Mixing these two meanings can be confusing
1921-
/// and [proposal]s exist to use `unsafe {}` blocks inside such functions when
1922-
/// making `unsafe` operations.
1924+
/// inside the function are upheld. Mixing these two meanings can be confusing, so the
1925+
/// `unsafe_op_in_unsafe_fn` lint can be enabled to warn against that and require explicit unsafe
1926+
/// blocks even inside `unsafe fn`.
19231927
///
19241928
/// See the [Rustnomicon] and the [Reference] for more information.
19251929
///
@@ -1987,13 +1991,16 @@ mod type_keyword {}
19871991
///
19881992
/// ```rust
19891993
/// # #![allow(dead_code)]
1994+
/// #![deny(unsafe_op_in_unsafe_fn)]
1995+
///
19901996
/// /// Dereference the given pointer.
19911997
/// ///
19921998
/// /// # Safety
19931999
/// ///
19942000
/// /// `ptr` must be aligned and must not be dangling.
19952001
/// unsafe fn deref_unchecked(ptr: *const i32) -> i32 {
1996-
/// *ptr
2002+
/// // SAFETY: the caller is required to ensure that `ptr` is aligned and dereferenceable.
2003+
/// unsafe { *ptr }
19972004
/// }
19982005
///
19992006
/// let a = 3;
@@ -2003,35 +2010,118 @@ mod type_keyword {}
20032010
/// unsafe { assert_eq!(*b, deref_unchecked(b)); };
20042011
/// ```
20052012
///
2006-
/// Traits marked as `unsafe` must be [`impl`]emented using `unsafe impl`. This
2007-
/// makes a guarantee to other `unsafe` code that the implementation satisfies
2008-
/// the trait's safety contract. The [Send] and [Sync] traits are examples of
2009-
/// this behaviour in the standard library.
2013+
/// ## `unsafe` and traits
2014+
///
2015+
/// The interactions of `unsafe` and traits can be surprising, so let us contrast the
2016+
/// two combinations of safe `fn` in `unsafe trait` and `unsafe fn` in safe trait using two
2017+
/// examples:
2018+
///
2019+
/// ```rust
2020+
/// /// # Safety
2021+
/// ///
2022+
/// /// `make_even` must return an even number.
2023+
/// unsafe trait MakeEven {
2024+
/// fn make_even(&self) -> i32;
2025+
/// }
2026+
///
2027+
/// // SAFETY: Our `make_even` always returns something even.
2028+
/// unsafe impl MakeEven for i32 {
2029+
/// fn make_even(&self) -> i32 {
2030+
/// self << 1
2031+
/// }
2032+
/// }
2033+
///
2034+
/// fn use_make_even(x: impl MakeEven) {
2035+
/// if x.make_even() % 2 == 1 {
2036+
/// // SAFETY: this can never happen, because all `MakeEven` implementations
2037+
/// // ensure that `make_even` returns something even.
2038+
/// unsafe { std::hint::unreachable_unchecked() };
2039+
/// }
2040+
/// }
2041+
/// ```
2042+
///
2043+
/// Note how the safety contract of the trait is upheld by the implementation, and is itself used to
2044+
/// uphold the safety contract of the unsafe function `unreachable_unchecked` called by
2045+
/// `use_make_even`. `make_even` itself is a safe function because its *callers* do not have to
2046+
/// worry about any contract, only the *implementation* of `MakeEven` is required to uphold a
2047+
/// certain contract. `use_make_even` is safe because it can use the promise made by `MakeEven`
2048+
/// implementations to uphold the safety contract of the `unsafe fn unreachable_unchecked` it calls.
2049+
///
2050+
/// It is also possible to have `unsafe fn` in a regular safe `trait`:
20102051
///
20112052
/// ```rust
2012-
/// /// Implementors of this trait must guarantee an element is always
2013-
/// /// accessible with index 3.
2014-
/// unsafe trait ThreeIndexable<T> {
2015-
/// /// Returns a reference to the element with index 3 in `&self`.
2016-
/// fn three(&self) -> &T;
2053+
/// # #![feature(never_type)]
2054+
/// #![deny(unsafe_op_in_unsafe_fn)]
2055+
///
2056+
/// trait Indexable {
2057+
/// const LEN: usize;
2058+
///
2059+
/// /// # Safety
2060+
/// ///
2061+
/// /// The caller must ensure that `idx < LEN`.
2062+
/// unsafe fn idx_unchecked(&self, idx: usize) -> i32;
20172063
/// }
20182064
///
2019-
/// // The implementation of `ThreeIndexable` for `[T; 4]` is `unsafe`
2020-
/// // because the implementor must abide by a contract the compiler cannot
2021-
/// // check but as a programmer we know there will always be a valid element
2022-
/// // at index 3 to access.
2023-
/// unsafe impl<T> ThreeIndexable<T> for [T; 4] {
2024-
/// fn three(&self) -> &T {
2025-
/// // SAFETY: implementing the trait means there always is an element
2026-
/// // with index 3 accessible.
2027-
/// unsafe { self.get_unchecked(3) }
2065+
/// // The implementation for `i32` doesn't need to do any contract reasoning.
2066+
/// impl Indexable for i32 {
2067+
/// const LEN: usize = 1;
2068+
///
2069+
/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
2070+
/// debug_assert_eq!(idx, 0);
2071+
/// *self
20282072
/// }
20292073
/// }
20302074
///
2031-
/// let a = [1, 2, 4, 8];
2032-
/// assert_eq!(a.three(), &8);
2075+
/// // The implementation for arrays exploits the function contract to
2076+
/// // make use of `get_unchecked` on slices and avoid a run-time check.
2077+
/// impl Indexable for [i32; 42] {
2078+
/// const LEN: usize = 42;
2079+
///
2080+
/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
2081+
/// // SAFETY: As per this trait's documentation, the caller ensures
2082+
/// // that `idx < 42`.
2083+
/// unsafe { *self.get_unchecked(idx) }
2084+
/// }
2085+
/// }
2086+
///
2087+
/// // The implementation for the never type declares a length of 0,
2088+
/// // which means `idx_unchecked` can never be called.
2089+
/// impl Indexable for ! {
2090+
/// const LEN: usize = 0;
2091+
///
2092+
/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
2093+
/// // SAFETY: As per this trait's documentation, the caller ensures
2094+
/// // that `idx < 0`, which is impossible, so this is dead code.
2095+
/// unsafe { std::hint::unreachable_unchecked() }
2096+
/// }
2097+
/// }
2098+
///
2099+
/// fn use_indexable<I: Indexable>(x: I, idx: usize) -> i32 {
2100+
/// if idx < I::LEN {
2101+
/// // SAFETY: We have checked that `idx < I::LEN`.
2102+
/// unsafe { x.idx_unchecked(idx) }
2103+
/// } else {
2104+
/// panic!("index out-of-bounds")
2105+
/// }
2106+
/// }
20332107
/// ```
20342108
///
2109+
/// This time, `use_indexable` is safe because it uses a run-time check to discharge the safety
2110+
/// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing
2111+
/// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation
2112+
/// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation
2113+
/// to contend with. Of course, the implementation of `Indexable` may choose to call other unsafe
2114+
/// operations, and then it needs an `unsafe` *block* to indicate it discharged the proof
2115+
/// obligations of its callees. (We enabled `unsafe_op_in_unsafe_fn`, so the body of `idx_unchecked`
2116+
/// is not implicitly an unsafe block.) For that purpose it can make use of the contract that all
2117+
/// its callers must uphold -- the fact that `idx < LEN`.
2118+
///
2119+
/// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond
2120+
/// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare
2121+
/// that some of its functions have *postconditions* that go beyond those encoded in the return type
2122+
/// (such as returning an even integer). If a trait needs a function with both extra precondition
2123+
/// and extra postcondition, then it needs an `unsafe fn` in an `unsafe trait`.
2124+
///
20352125
/// [`extern`]: keyword.extern.html
20362126
/// [`trait`]: keyword.trait.html
20372127
/// [`static`]: keyword.static.html
@@ -2043,7 +2133,6 @@ mod type_keyword {}
20432133
/// [nomicon-soundness]: ../nomicon/safe-unsafe-meaning.html
20442134
/// [soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library
20452135
/// [Reference]: ../reference/unsafety.html
2046-
/// [proposal]: https://github.com/rust-lang/rfcs/pull/2585
20472136
/// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696
20482137
mod unsafe_keyword {}
20492138

‎src/ci/scripts/should-skip-this.sh‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then
1919
# those files are present in the diff a submodule was updated.
2020
echo "Submodules were updated"
2121
elif ! (git diff --quiet "$BASE_COMMIT" -- \
22-
src/tools/clippy src/tools/rustfmt src/tools/miri); then
22+
src/tools/clippy src/tools/rustfmt src/tools/miri
23+
library/std/src/sys); then
2324
# There is not an easy blanket search for subtrees. For now, manually list
2425
# the subtrees.
26+
# Also run this when the platform-specific parts of std change, in case
27+
# that breaks Miri.
2528
echo "Tool subtrees were updated"
2629
elif ! (git diff --quiet "$BASE_COMMIT" -- \
2730
src/test/rustdoc-gui \
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(generic_const_exprs)]
2+
#![allow(incomplete_features)]
3+
4+
trait X {
5+
type Y<'a>;
6+
}
7+
8+
const _: () = {
9+
fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
10+
//~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
11+
//~| ERROR this associated type takes 0 generic arguments but 1 generic argument
12+
};
13+
14+
fn main() {}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
2+
--> $DIR/issue-102768.rs:9:30
3+
|
4+
LL | fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
5+
| ^ expected 1 lifetime argument
6+
|
7+
note: associated type defined here, with 1 lifetime parameter: `'a`
8+
--> $DIR/issue-102768.rs:5:10
9+
|
10+
LL | type Y<'a>;
11+
| ^ --
12+
help: add missing lifetime argument
13+
|
14+
LL | fn f2<'a>(arg: Box<dyn X<Y<'a, 1> = &'a ()>>) {}
15+
| +++
16+
17+
error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
18+
--> $DIR/issue-102768.rs:9:30
19+
|
20+
LL | fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
21+
| ^--- help: remove these generics
22+
| |
23+
| expected 0 generic arguments
24+
|
25+
note: associated type defined here, with 0 generic parameters
26+
--> $DIR/issue-102768.rs:5:10
27+
|
28+
LL | type Y<'a>;
29+
| ^
30+
31+
error: aborting due to 2 previous errors
32+
33+
For more information about this error, try `rustc --explain E0107`.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// compile-flags: --crate-type=lib
2+
// This test checks that the `where_clauses_object_safety` lint does not cause
3+
// other object safety *hard errors* to be suppressed, because we currently
4+
// only emit one object safety error per trait...
5+
6+
use std::future::Future;
7+
use std::pin::Pin;
8+
9+
pub trait Fetcher: Send + Sync {
10+
fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
11+
where
12+
Self: Sync,
13+
{
14+
todo!()
15+
}
16+
}
17+
18+
fn fetcher() -> Box<dyn Fetcher> {
19+
//~^ ERROR the trait `Fetcher` cannot be made into an object
20+
todo!()
21+
}
22+
23+
pub fn foo() {
24+
let fetcher = fetcher();
25+
let _ = fetcher.get();
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0038]: the trait `Fetcher` cannot be made into an object
2+
--> $DIR/issue-102762.rs:18:21
3+
|
4+
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
5+
| ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
6+
...
7+
LL | fn fetcher() -> Box<dyn Fetcher> {
8+
| ^^^^^^^^^^^ `Fetcher` cannot be made into an object
9+
|
10+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
11+
--> $DIR/issue-102762.rs:10:22
12+
|
13+
LL | pub trait Fetcher: Send + Sync {
14+
| ------- this trait cannot be made into an object...
15+
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
16+
| ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)
Please sign in to comment.