Skip to content

Commit befabbc

Browse files
committedMay 3, 2024
Auto merge of #124675 - matthiaskrgr:rollup-x6n79ua, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #122492 (Implement ptr_as_ref_unchecked) - #123815 (Fix cannot usage in time.rs) - #124059 (default_alloc_error_hook: explain difference to default __rdl_oom in alloc) - #124510 (Add raw identifier in a typo suggestion) - #124555 (coverage: Clean up creation of MC/DC condition bitmaps) - #124593 (Describe and use CStr literals in CStr and CString docs) - #124630 (CI: remove `env-x86_64-apple-tests` YAML anchor) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 0d7b2fb + 56b2989 commit befabbc

File tree

18 files changed

+303
-91
lines changed

18 files changed

+303
-91
lines changed
 

Diff for: ‎compiler/rustc_abi/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use rustc_macros::{Decodable_Generic, Encodable_Generic};
2121
use std::iter::Step;
2222

2323
mod layout;
24+
#[cfg(test)]
25+
mod tests;
2426

2527
pub use layout::LayoutCalculator;
2628

Diff for: ‎compiler/rustc_abi/src/tests.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use super::*;
2+
3+
#[test]
4+
fn align_constants() {
5+
assert_eq!(Align::ONE, Align::from_bytes(1).unwrap());
6+
assert_eq!(Align::EIGHT, Align::from_bytes(8).unwrap());
7+
}

Diff for: ‎compiler/rustc_codegen_llvm/src/builder.rs

+12-24
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_data_structures::small_c_str::SmallCStr;
1717
use rustc_hir::def_id::DefId;
1818
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
1919
use rustc_middle::ty::layout::{
20-
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout,
20+
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
2121
};
2222
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
2323
use rustc_sanitizers::{cfi, kcfi};
@@ -27,7 +27,6 @@ use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
2727
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
2828
use smallvec::SmallVec;
2929
use std::borrow::Cow;
30-
use std::ffi::CString;
3130
use std::iter;
3231
use std::ops::Deref;
3332
use std::ptr;
@@ -1705,13 +1704,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
17051704
kcfi_bundle
17061705
}
17071706

1707+
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
1708+
///
1709+
/// This doesn't produce any code directly, but is used as input by
1710+
/// the LLVM pass that handles coverage instrumentation.
1711+
///
1712+
/// (See clang's [`CodeGenPGO::emitMCDCParameters`] for comparison.)
1713+
///
1714+
/// [`CodeGenPGO::emitMCDCParameters`]:
1715+
/// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124
17081716
pub(crate) fn mcdc_parameters(
17091717
&mut self,
17101718
fn_name: &'ll Value,
17111719
hash: &'ll Value,
17121720
bitmap_bytes: &'ll Value,
1713-
max_decision_depth: u32,
1714-
) -> Vec<&'ll Value> {
1721+
) {
17151722
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes);
17161723

17171724
assert!(llvm_util::get_version() >= (18, 0, 0), "MCDC intrinsics require LLVM 18 or later");
@@ -1724,8 +1731,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
17241731
let args = &[fn_name, hash, bitmap_bytes];
17251732
let args = self.check_call("call", llty, llfn, args);
17261733

1727-
let mut cond_bitmaps = vec![];
1728-
17291734
unsafe {
17301735
let _ = llvm::LLVMRustBuildCall(
17311736
self.llbuilder,
@@ -1736,23 +1741,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
17361741
[].as_ptr(),
17371742
0 as c_uint,
17381743
);
1739-
// Create condition bitmap named `mcdc.addr`.
1740-
for i in 0..=max_decision_depth {
1741-
let mut bx = Builder::with_cx(self.cx);
1742-
bx.position_at_start(llvm::LLVMGetFirstBasicBlock(self.llfn()));
1743-
1744-
let name = CString::new(format!("mcdc.addr.{i}")).unwrap();
1745-
let cond_bitmap = {
1746-
let alloca =
1747-
llvm::LLVMBuildAlloca(bx.llbuilder, bx.cx.type_i32(), name.as_ptr());
1748-
llvm::LLVMSetAlignment(alloca, 4);
1749-
alloca
1750-
};
1751-
bx.store(self.const_i32(0), cond_bitmap, self.tcx().data_layout.i32_align.abi);
1752-
cond_bitmaps.push(cond_bitmap);
1753-
}
17541744
}
1755-
cond_bitmaps
17561745
}
17571746

17581747
pub(crate) fn mcdc_tvbitmap_update(
@@ -1794,8 +1783,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
17941783
0 as c_uint,
17951784
);
17961785
}
1797-
let i32_align = self.tcx().data_layout.i32_align.abi;
1798-
self.store(self.const_i32(0), mcdc_temp, i32_align);
1786+
self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
17991787
}
18001788

18011789
pub(crate) fn mcdc_condbitmap_update(

Diff for: ‎compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

+38-28
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ use rustc_codegen_ssa::traits::{
1313
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
1414
use rustc_llvm::RustString;
1515
use rustc_middle::bug;
16-
use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo};
16+
use rustc_middle::mir::coverage::CoverageKind;
1717
use rustc_middle::ty::layout::HasTyCtxt;
1818
use rustc_middle::ty::Instance;
19-
use rustc_target::abi::Align;
19+
use rustc_target::abi::{Align, Size};
2020

2121
use std::cell::RefCell;
2222

@@ -91,6 +91,42 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
9191
}
9292

9393
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
94+
fn init_coverage(&mut self, instance: Instance<'tcx>) {
95+
let Some(function_coverage_info) =
96+
self.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
97+
else {
98+
return;
99+
};
100+
101+
// If there are no MC/DC bitmaps to set up, return immediately.
102+
if function_coverage_info.mcdc_bitmap_bytes == 0 {
103+
return;
104+
}
105+
106+
let fn_name = self.get_pgo_func_name_var(instance);
107+
let hash = self.const_u64(function_coverage_info.function_source_hash);
108+
let bitmap_bytes = self.const_u32(function_coverage_info.mcdc_bitmap_bytes);
109+
self.mcdc_parameters(fn_name, hash, bitmap_bytes);
110+
111+
// Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps.
112+
let mut cond_bitmaps = vec![];
113+
for i in 0..function_coverage_info.mcdc_num_condition_bitmaps {
114+
// MC/DC intrinsics will perform loads/stores that use the ABI default
115+
// alignment for i32, so our variable declaration should match.
116+
let align = self.tcx.data_layout.i32_align.abi;
117+
let cond_bitmap = self.alloca(Size::from_bytes(4), align);
118+
llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes());
119+
self.store(self.const_i32(0), cond_bitmap, align);
120+
cond_bitmaps.push(cond_bitmap);
121+
}
122+
123+
self.coverage_context()
124+
.expect("always present when coverage is enabled")
125+
.mcdc_condition_bitmap_map
126+
.borrow_mut()
127+
.insert(instance, cond_bitmaps);
128+
}
129+
94130
#[instrument(level = "debug", skip(self))]
95131
fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
96132
// Our caller should have already taken care of inlining subtleties,
@@ -109,10 +145,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
109145
return;
110146
};
111147

112-
if function_coverage_info.mcdc_bitmap_bytes > 0 {
113-
ensure_mcdc_parameters(bx, instance, function_coverage_info);
114-
}
115-
116148
let Some(coverage_context) = bx.coverage_context() else { return };
117149
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
118150
let func_coverage = coverage_map
@@ -193,28 +225,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
193225
}
194226
}
195227

196-
fn ensure_mcdc_parameters<'ll, 'tcx>(
197-
bx: &mut Builder<'_, 'll, 'tcx>,
198-
instance: Instance<'tcx>,
199-
function_coverage_info: &FunctionCoverageInfo,
200-
) {
201-
let Some(cx) = bx.coverage_context() else { return };
202-
if cx.mcdc_condition_bitmap_map.borrow().contains_key(&instance) {
203-
return;
204-
}
205-
206-
let fn_name = bx.get_pgo_func_name_var(instance);
207-
let hash = bx.const_u64(function_coverage_info.function_source_hash);
208-
let bitmap_bytes = bx.const_u32(function_coverage_info.mcdc_bitmap_bytes);
209-
let max_decision_depth = function_coverage_info.mcdc_max_decision_depth;
210-
let cond_bitmap = bx.mcdc_parameters(fn_name, hash, bitmap_bytes, max_decision_depth as u32);
211-
bx.coverage_context()
212-
.expect("already checked above")
213-
.mcdc_condition_bitmap_map
214-
.borrow_mut()
215-
.insert(instance, cond_bitmap);
216-
}
217-
218228
/// Calls llvm::createPGOFuncNameVar() with the given function instance's
219229
/// mangled function name. The LLVM API returns an llvm::GlobalVariable
220230
/// containing the function name, with the specific variable name and linkage

Diff for: ‎compiler/rustc_codegen_ssa/src/mir/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
259259
// Apply debuginfo to the newly allocated locals.
260260
fx.debug_introduce_locals(&mut start_bx);
261261

262+
// If the backend supports coverage, and coverage is enabled for this function,
263+
// do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps).
264+
start_bx.init_coverage(instance);
265+
262266
// The builders will be created separately for each basic block at `codegen_block`.
263267
// So drop the builder of `start_llbb` to avoid having two at the same time.
264268
drop(start_bx);

Diff for: ‎compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ use rustc_middle::mir::coverage::CoverageKind;
33
use rustc_middle::ty::Instance;
44

55
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
6+
/// Performs any start-of-function codegen needed for coverage instrumentation.
7+
///
8+
/// Can be a no-op in backends that don't support coverage instrumentation.
9+
fn init_coverage(&mut self, _instance: Instance<'tcx>) {}
10+
611
/// Handle the MIR coverage info in a backend-specific way.
712
///
813
/// This can potentially be a no-op in backends that don't support

Diff for: ‎compiler/rustc_middle/src/mir/coverage.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ pub struct FunctionCoverageInfo {
277277
pub mappings: Vec<Mapping>,
278278
/// The depth of the deepest decision is used to know how many
279279
/// temp condbitmaps should be allocated for the function.
280-
pub mcdc_max_decision_depth: u16,
280+
pub mcdc_num_condition_bitmaps: usize,
281281
}
282282

283283
/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR.

Diff for: ‎compiler/rustc_mir_transform/src/coverage/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,23 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
102102

103103
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans);
104104

105-
let mcdc_max_decision_depth = coverage_spans
105+
let mcdc_num_condition_bitmaps = coverage_spans
106106
.mappings
107107
.iter()
108108
.filter_map(|bcb_mapping| match bcb_mapping.kind {
109109
BcbMappingKind::MCDCDecision { decision_depth, .. } => Some(decision_depth),
110110
_ => None,
111111
})
112112
.max()
113-
.unwrap_or(0);
113+
.map_or(0, |max| usize::from(max) + 1);
114114

115115
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
116116
function_source_hash: hir_info.function_source_hash,
117117
num_counters: coverage_counters.num_counters(),
118118
mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(),
119119
expressions: coverage_counters.into_expressions(),
120120
mappings,
121-
mcdc_max_decision_depth,
121+
mcdc_num_condition_bitmaps,
122122
}));
123123
}
124124

Diff for: ‎compiler/rustc_resolve/src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1617,7 +1617,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16171617
let post = format!(", consider renaming `{}` into `{snippet}`", suggestion.candidate);
16181618
(span, snippet, post)
16191619
} else {
1620-
(span, suggestion.candidate.to_string(), String::new())
1620+
(span, suggestion.candidate.to_ident_string(), String::new())
16211621
};
16221622
let msg = match suggestion.target {
16231623
SuggestionTarget::SimilarlyNamed => format!(

Diff for: ‎library/alloc/src/ffi/c_str.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use crate::sync::Arc;
4141
/// or anything that implements <code>[Into]<[Vec]<[u8]>></code> (for
4242
/// example, you can build a `CString` straight out of a [`String`] or
4343
/// a <code>&[str]</code>, since both implement that trait).
44+
/// You can create a `CString` from a literal with `CString::from(c"Text")`.
4445
///
4546
/// The [`CString::new`] method will actually check that the provided <code>&[[u8]]</code>
4647
/// does not have 0 bytes in the middle, and return an error if it
@@ -1069,27 +1070,22 @@ impl CStr {
10691070
///
10701071
/// # Examples
10711072
///
1072-
/// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
1073+
/// Calling `to_string_lossy` on a `CStr` containing valid UTF-8. The leading
1074+
/// `c` on the string literal denotes a `CStr`.
10731075
///
10741076
/// ```
10751077
/// use std::borrow::Cow;
1076-
/// use std::ffi::CStr;
10771078
///
1078-
/// let cstr = CStr::from_bytes_with_nul(b"Hello World\0")
1079-
/// .expect("CStr::from_bytes_with_nul failed");
1080-
/// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World"));
1079+
/// assert_eq!(c"Hello World".to_string_lossy(), Cow::Borrowed("Hello World"));
10811080
/// ```
10821081
///
10831082
/// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
10841083
///
10851084
/// ```
10861085
/// use std::borrow::Cow;
1087-
/// use std::ffi::CStr;
10881086
///
1089-
/// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
1090-
/// .expect("CStr::from_bytes_with_nul failed");
10911087
/// assert_eq!(
1092-
/// cstr.to_string_lossy(),
1088+
/// c"Hello \xF0\x90\x80World".to_string_lossy(),
10931089
/// Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
10941090
/// );
10951091
/// ```

Diff for: ‎library/core/src/ffi/c_str.rs

+24-13
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,32 @@ use crate::str;
2323
///
2424
/// This type represents a borrowed reference to a nul-terminated
2525
/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
26-
/// slice, or unsafely from a raw `*const c_char`. It can then be
27-
/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
28-
/// into an owned `CString`.
26+
/// slice, or unsafely from a raw `*const c_char`. It can be expressed as a
27+
/// literal in the form `c"Hello world"`.
28+
///
29+
/// The `CStr` can then be converted to a Rust <code>&[str]</code> by performing
30+
/// UTF-8 validation, or into an owned `CString`.
2931
///
3032
/// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former
3133
/// in each pair are borrowed references; the latter are owned
3234
/// strings.
3335
///
3436
/// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)`
35-
/// notwithstanding) and is not recommended to be placed in the signatures of FFI functions.
36-
/// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor
37-
/// to provide a safe interface to other consumers.
37+
/// notwithstanding) and should not be placed in the signatures of FFI functions.
38+
/// Instead, safe wrappers of FFI functions may leverage [`CStr::as_ptr`] and the unsafe
39+
/// [`CStr::from_ptr`] constructor to provide a safe interface to other consumers.
3840
///
3941
/// # Examples
4042
///
4143
/// Inspecting a foreign C string:
4244
///
43-
/// ```ignore (extern-declaration)
45+
/// ```
4446
/// use std::ffi::CStr;
4547
/// use std::os::raw::c_char;
4648
///
49+
/// # /* Extern functions are awkward in doc comments - fake it instead
4750
/// extern "C" { fn my_string() -> *const c_char; }
51+
/// # */ unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() }
4852
///
4953
/// unsafe {
5054
/// let slice = CStr::from_ptr(my_string());
@@ -54,12 +58,14 @@ use crate::str;
5458
///
5559
/// Passing a Rust-originating C string:
5660
///
57-
/// ```ignore (extern-declaration)
61+
/// ```
5862
/// use std::ffi::{CString, CStr};
5963
/// use std::os::raw::c_char;
6064
///
6165
/// fn work(data: &CStr) {
66+
/// # /* Extern functions are awkward in doc comments - fake it instead
6267
/// extern "C" { fn work_with(data: *const c_char); }
68+
/// # */ unsafe extern "C" fn work_with(s: *const c_char) {}
6369
///
6470
/// unsafe { work_with(data.as_ptr()) }
6571
/// }
@@ -70,11 +76,13 @@ use crate::str;
7076
///
7177
/// Converting a foreign C string into a Rust `String`:
7278
///
73-
/// ```ignore (extern-declaration)
79+
/// ```
7480
/// use std::ffi::CStr;
7581
/// use std::os::raw::c_char;
7682
///
83+
/// # /* Extern functions are awkward in doc comments - fake it instead
7784
/// extern "C" { fn my_string() -> *const c_char; }
85+
/// # */ unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() }
7886
///
7987
/// fn my_string_safe() -> String {
8088
/// let cstr = unsafe { CStr::from_ptr(my_string()) };
@@ -241,16 +249,16 @@ impl CStr {
241249
///
242250
/// # Examples
243251
///
244-
/// ```ignore (extern-declaration)
252+
/// ```
245253
/// use std::ffi::{c_char, CStr};
246254
///
247-
/// extern "C" {
248-
/// fn my_string() -> *const c_char;
255+
/// fn my_string() -> *const c_char {
256+
/// c"hello".as_ptr()
249257
/// }
250258
///
251259
/// unsafe {
252260
/// let slice = CStr::from_ptr(my_string());
253-
/// println!("string returned: {}", slice.to_str().unwrap());
261+
/// assert_eq!(slice.to_str().unwrap(), "hello");
254262
/// }
255263
/// ```
256264
///
@@ -264,6 +272,8 @@ impl CStr {
264272
/// BYTES.as_ptr().cast()
265273
/// };
266274
/// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
275+
///
276+
/// assert_eq!(c"Hello, world!", HELLO);
267277
/// ```
268278
///
269279
/// [valid]: core::ptr#safety
@@ -549,6 +559,7 @@ impl CStr {
549559
///
550560
/// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
551561
/// assert!(empty_cstr.is_empty());
562+
/// assert!(c"".is_empty());
552563
/// # Ok(())
553564
/// # }
554565
/// ```

Diff for: ‎library/core/src/ptr/const_ptr.rs

+48
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,54 @@ impl<T: ?Sized> *const T {
358358
if self.is_null() { None } else { unsafe { Some(&*self) } }
359359
}
360360

361+
/// Returns a shared reference to the value behind the pointer.
362+
/// If the pointer may be null or the value may be uninitialized, [`as_uninit_ref`] must be used instead.
363+
/// If the pointer may be null, but the value is known to have been initialized, [`as_ref`] must be used instead.
364+
///
365+
/// [`as_ref`]: #method.as_ref
366+
/// [`as_uninit_ref`]: #method.as_uninit_ref
367+
///
368+
/// # Safety
369+
///
370+
/// When calling this method, you have to ensure that all of the following is true:
371+
///
372+
/// * The pointer must be properly aligned.
373+
///
374+
/// * It must be "dereferenceable" in the sense defined in [the module documentation].
375+
///
376+
/// * The pointer must point to an initialized instance of `T`.
377+
///
378+
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
379+
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
380+
/// In particular, while this reference exists, the memory the pointer points to must
381+
/// not get mutated (except inside `UnsafeCell`).
382+
///
383+
/// This applies even if the result of this method is unused!
384+
/// (The part about being initialized is not yet fully decided, but until
385+
/// it is, the only safe approach is to ensure that they are indeed initialized.)
386+
///
387+
/// [the module documentation]: crate::ptr#safety
388+
///
389+
/// # Examples
390+
///
391+
/// ```
392+
/// #![feature(ptr_as_ref_unchecked)]
393+
/// let ptr: *const u8 = &10u8 as *const u8;
394+
///
395+
/// unsafe {
396+
/// println!("We got back the value: {}!", ptr.as_ref_unchecked());
397+
/// }
398+
/// ```
399+
// FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized.
400+
#[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
401+
#[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
402+
#[inline]
403+
#[must_use]
404+
pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T {
405+
// SAFETY: the caller must guarantee that `self` is valid for a reference
406+
unsafe { &*self }
407+
}
408+
361409
/// Returns `None` if the pointer is null, or else returns a shared reference to
362410
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
363411
/// that the value has to be initialized.

Diff for: ‎library/core/src/ptr/mut_ptr.rs

+103
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,57 @@ impl<T: ?Sized> *mut T {
367367
if self.is_null() { None } else { unsafe { Some(&*self) } }
368368
}
369369

370+
/// Returns a shared reference to the value behind the pointer.
371+
/// If the pointer may be null or the value may be uninitialized, [`as_uninit_ref`] must be used instead.
372+
/// If the pointer may be null, but the value is known to have been initialized, [`as_ref`] must be used instead.
373+
///
374+
/// For the mutable counterpart see [`as_mut_unchecked`].
375+
///
376+
/// [`as_ref`]: #method.as_ref
377+
/// [`as_uninit_ref`]: #method.as_uninit_ref
378+
/// [`as_mut_unchecked`]: #method.as_mut_unchecked
379+
///
380+
/// # Safety
381+
///
382+
/// When calling this method, you have to ensure that all of the following is true:
383+
///
384+
/// * The pointer must be properly aligned.
385+
///
386+
/// * It must be "dereferenceable" in the sense defined in [the module documentation].
387+
///
388+
/// * The pointer must point to an initialized instance of `T`.
389+
///
390+
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
391+
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
392+
/// In particular, while this reference exists, the memory the pointer points to must
393+
/// not get mutated (except inside `UnsafeCell`).
394+
///
395+
/// This applies even if the result of this method is unused!
396+
/// (The part about being initialized is not yet fully decided, but until
397+
/// it is, the only safe approach is to ensure that they are indeed initialized.)
398+
///
399+
/// [the module documentation]: crate::ptr#safety
400+
///
401+
/// # Examples
402+
///
403+
/// ```
404+
/// #![feature(ptr_as_ref_unchecked)]
405+
/// let ptr: *mut u8 = &mut 10u8 as *mut u8;
406+
///
407+
/// unsafe {
408+
/// println!("We got back the value: {}!", ptr.as_ref_unchecked());
409+
/// }
410+
/// ```
411+
// FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized.
412+
#[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
413+
#[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
414+
#[inline]
415+
#[must_use]
416+
pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T {
417+
// SAFETY: the caller must guarantee that `self` is valid for a reference
418+
unsafe { &*self }
419+
}
420+
370421
/// Returns `None` if the pointer is null, or else returns a shared reference to
371422
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
372423
/// that the value has to be initialized.
@@ -688,6 +739,58 @@ impl<T: ?Sized> *mut T {
688739
if self.is_null() { None } else { unsafe { Some(&mut *self) } }
689740
}
690741

742+
/// Returns a unique reference to the value behind the pointer.
743+
/// If the pointer may be null or the value may be uninitialized, [`as_uninit_mut`] must be used instead.
744+
/// If the pointer may be null, but the value is known to have been initialized, [`as_mut`] must be used instead.
745+
///
746+
/// For the shared counterpart see [`as_ref_unchecked`].
747+
///
748+
/// [`as_mut`]: #method.as_mut
749+
/// [`as_uninit_mut`]: #method.as_uninit_mut
750+
/// [`as_ref_unchecked`]: #method.as_mut_unchecked
751+
///
752+
/// # Safety
753+
///
754+
/// When calling this method, you have to ensure that all of the following is true:
755+
///
756+
/// * The pointer must be properly aligned.
757+
///
758+
/// * It must be "dereferenceable" in the sense defined in [the module documentation].
759+
///
760+
/// * The pointer must point to an initialized instance of `T`.
761+
///
762+
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
763+
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
764+
/// In particular, while this reference exists, the memory the pointer points to must
765+
/// not get mutated (except inside `UnsafeCell`).
766+
///
767+
/// This applies even if the result of this method is unused!
768+
/// (The part about being initialized is not yet fully decided, but until
769+
/// it is, the only safe approach is to ensure that they are indeed initialized.)
770+
///
771+
/// [the module documentation]: crate::ptr#safety
772+
///
773+
/// # Examples
774+
///
775+
/// ```
776+
/// #![feature(ptr_as_ref_unchecked)]
777+
/// let mut s = [1, 2, 3];
778+
/// let ptr: *mut u32 = s.as_mut_ptr();
779+
/// let first_value = unsafe { ptr.as_mut_unchecked() };
780+
/// *first_value = 4;
781+
/// # assert_eq!(s, [4, 2, 3]);
782+
/// println!("{s:?}"); // It'll print: "[4, 2, 3]".
783+
/// ```
784+
// FIXME: mention it in the docs for `as_mut` and `as_uninit_mut` once stabilized.
785+
#[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
786+
#[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
787+
#[inline]
788+
#[must_use]
789+
pub const unsafe fn as_mut_unchecked<'a>(self) -> &'a mut T {
790+
// SAFETY: the caller must guarantee that `self` is valid for a reference
791+
unsafe { &mut *self }
792+
}
793+
691794
/// Returns `None` if the pointer is null, or else returns a unique reference to
692795
/// the value wrapped in `Some`. In contrast to [`as_mut`], this does not require
693796
/// that the value has to be initialized.

Diff for: ‎library/core/src/time.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1437,10 +1437,10 @@ impl TryFromFloatSecsError {
14371437
const fn description(&self) -> &'static str {
14381438
match self.kind {
14391439
TryFromFloatSecsErrorKind::Negative => {
1440-
"can not convert float seconds to Duration: value is negative"
1440+
"cannot convert float seconds to Duration: value is negative"
14411441
}
14421442
TryFromFloatSecsErrorKind::OverflowOrNan => {
1443-
"can not convert float seconds to Duration: value is either too big or NaN"
1443+
"cannot convert float seconds to Duration: value is either too big or NaN"
14441444
}
14451445
}
14461446
}

Diff for: ‎library/std/src/alloc.rs

+6
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,12 @@ fn default_alloc_error_hook(layout: Layout) {
353353
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
354354
panic!("memory allocation of {} bytes failed", layout.size());
355355
} else {
356+
// This is the default path taken on OOM, and the only path taken on stable with std.
357+
// Crucially, it does *not* call any user-defined code, and therefore users do not have to
358+
// worry about allocation failure causing reentrancy issues. That makes it different from
359+
// the default `__rdl_oom` defined in alloc (i.e., the default alloc error handler that is
360+
// called when there is no `#[alloc_error_handler]`), which triggers a regular panic and
361+
// thus can invoke a user-defined panic hook, executing arbitrary user-defined code.
356362
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
357363
}
358364
}

Diff for: ‎src/ci/github-actions/jobs.yml

+13-10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ runners:
3636
os: [ self-hosted, ARM64, linux ]
3737

3838
envs:
39+
env-x86_64-apple-tests: &env-x86_64-apple-tests
40+
SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps
41+
RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
42+
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
43+
MACOSX_DEPLOYMENT_TARGET: 10.12
44+
MACOSX_STD_DEPLOYMENT_TARGET: 10.12
45+
SELECT_XCODE: /Applications/Xcode_14.3.1.app
46+
NO_LLVM_ASSERTIONS: 1
47+
NO_DEBUG_ASSERTIONS: 1
48+
NO_OVERFLOW_CHECKS: 1
49+
3950
production:
4051
&production
4152
DEPLOY_BUCKET: rust-lang-ci2
@@ -272,16 +283,8 @@ auto:
272283
<<: *job-macos-xl
273284

274285
- image: x86_64-apple-1
275-
env: &env-x86_64-apple-tests
276-
SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps
277-
RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
278-
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
279-
MACOSX_DEPLOYMENT_TARGET: 10.12
280-
MACOSX_STD_DEPLOYMENT_TARGET: 10.12
281-
SELECT_XCODE: /Applications/Xcode_14.3.1.app
282-
NO_LLVM_ASSERTIONS: 1
283-
NO_DEBUG_ASSERTIONS: 1
284-
NO_OVERFLOW_CHECKS: 1
286+
env:
287+
<<: *env-x86_64-apple-tests
285288
<<: *job-macos-xl
286289

287290
- image: x86_64-apple-2

Diff for: ‎tests/ui/span/suggestion-raw-68962.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn r#fn() {}
2+
3+
fn main() {
4+
let r#final = 1;
5+
6+
// Should correctly suggest variable defined using raw identifier.
7+
fina; //~ ERROR cannot find value
8+
9+
// Should correctly suggest function defined using raw identifier.
10+
f(); //~ ERROR cannot find function
11+
}

Diff for: ‎tests/ui/span/suggestion-raw-68962.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0425]: cannot find value `fina` in this scope
2+
--> $DIR/suggestion-raw-68962.rs:7:5
3+
|
4+
LL | fina;
5+
| ^^^^ help: a local variable with a similar name exists: `r#final`
6+
7+
error[E0425]: cannot find function `f` in this scope
8+
--> $DIR/suggestion-raw-68962.rs:10:5
9+
|
10+
LL | fn r#fn() {}
11+
| --------- similarly named function `r#fn` defined here
12+
...
13+
LL | f();
14+
| ^ help: a function with a similar name exists: `r#fn`
15+
16+
error: aborting due to 2 previous errors
17+
18+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)
Please sign in to comment.