Skip to content

Commit f81797f

Browse files
committed
Auto merge of #155872 - JonathanBrouwer:rollup-syHc7Hm, r=JonathanBrouwer
Rollup of 4 pull requests Successful merges: - #152487 (core: drop unmapped ZSTs in array `map`) - #155716 (arm64e: set ptrauth ABI subtype on lib.rmeta Mach-O objects) - #155864 (Fix panic for doc attributes on where predicates) - #155865 (add test for accidentally fixed `binius_field` issue)
2 parents 2f43fe4 + 88046e0 commit f81797f

13 files changed

Lines changed: 214 additions & 31 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/doc.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,9 @@ impl DocParser {
701701
for i in items.mixed() {
702702
match i {
703703
MetaItemOrLitParser::MetaItemParser(mip) => {
704+
if self.nb_doc_attrs == 0 {
705+
self.attribute.first_span = cx.attr_span;
706+
}
704707
self.nb_doc_attrs += 1;
705708
self.parse_single_doc_attr_item(cx, mip);
706709
}

compiler/rustc_attr_parsing/src/target_checking.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,15 +292,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
292292
// in where clauses. After that, this function would become useless.
293293
let spans = attrs
294294
.into_iter()
295-
// FIXME: We shouldn't need to special-case `doc`!
296-
.filter(|attr| {
297-
matches!(
298-
attr,
299-
Attribute::Parsed(AttributeKind::DocComment { .. } | AttributeKind::Doc(_))
300-
| Attribute::Unparsed(_)
301-
)
295+
.filter_map(|attr| {
296+
match attr {
297+
Attribute::Parsed(AttributeKind::DocComment { span, .. }) => Some(*span),
298+
// FIXME: We shouldn't need to special-case `doc`!
299+
Attribute::Parsed(AttributeKind::Doc(attr)) => Some(attr.first_span),
300+
// Checked during attribute parsing target checking
301+
Attribute::Parsed(_) => None,
302+
Attribute::Unparsed(attr) => Some(attr.span),
303+
}
302304
})
303-
.map(|attr| attr.span())
304305
.collect::<Vec<_>>();
305306
if !spans.is_empty() {
306307
self.dcx()

compiler/rustc_codegen_ssa/src/back/metadata.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
216216
file.set_sub_architecture(sub_architecture);
217217
if sess.target.is_like_darwin {
218218
if macho_is_arm64e(&sess.target) {
219-
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
219+
file.set_macho_cpu_subtype(
220+
object::macho::CPU_SUBTYPE_ARM64E | object::macho::CPU_SUBTYPE_PTRAUTH_ABI,
221+
);
220222
}
221223

222224
file.set_macho_build_version(macho_object_build_version_for_target(sess))

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,8 @@ pub struct CfgHideShow {
544544

545545
#[derive(Clone, Debug, Default, HashStable_Generic, Decodable, PrintAttribute)]
546546
pub struct DocAttribute {
547+
pub first_span: Span,
548+
547549
pub aliases: FxIndexMap<Symbol, Span>,
548550
pub hidden: Option<Span>,
549551
// Because we need to emit the error if there is more than one `inline` attribute on an item
@@ -581,6 +583,7 @@ pub struct DocAttribute {
581583
impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute {
582584
fn encode(&self, encoder: &mut E) {
583585
let DocAttribute {
586+
first_span,
584587
aliases,
585588
hidden,
586589
inline,
@@ -603,6 +606,7 @@ impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute
603606
test_attrs,
604607
no_crate_inject,
605608
} = self;
609+
rustc_serialize::Encodable::<E>::encode(first_span, encoder);
606610
rustc_serialize::Encodable::<E>::encode(aliases, encoder);
607611
rustc_serialize::Encodable::<E>::encode(hidden, encoder);
608612

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
10271027
/// [`check_doc_inline`]: Self::check_doc_inline
10281028
fn check_doc_attrs(&self, attr: &DocAttribute, hir_id: HirId, target: Target) {
10291029
let DocAttribute {
1030+
first_span: _,
10301031
aliases,
10311032
// valid pretty much anywhere, not checked here?
10321033
// FIXME: should we?

library/core/src/array/drain.rs

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::marker::{Destruct, PhantomData};
2-
use crate::mem::{ManuallyDrop, SizedTypeProperties, conjure_zst};
3-
use crate::ptr::{NonNull, drop_in_place, from_raw_parts_mut, null_mut};
2+
use crate::mem::{ManuallyDrop, SizedTypeProperties, conjure_zst, transmute};
3+
use crate::ptr::{NonNull, drop_in_place, from_raw_parts_mut, without_provenance_mut};
44

5-
impl<'l, 'f, T, U, const N: usize, F: FnMut(T) -> U> Drain<'l, 'f, T, N, F> {
5+
impl<'l, 'f, T, U, F: FnMut(T) -> U> Drain<'l, 'f, T, F> {
66
/// This function returns a function that lets you index the given array in const.
77
/// As implemented it can optimize better than iterators, and can be constified.
88
/// It acts like a sort of guard (owns the array) and iterator combined, which can be implemented
@@ -14,43 +14,46 @@ impl<'l, 'f, T, U, const N: usize, F: FnMut(T) -> U> Drain<'l, 'f, T, N, F> {
1414
/// This will also not actually store the array.
1515
///
1616
/// SAFETY: must only be called `N` times. Thou shalt not drop the array either.
17-
// FIXME(const-hack): this is a hack for `let guard = Guard(array); |i| f(guard[i])`.
1817
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
19-
pub(super) const unsafe fn new(array: &'l mut ManuallyDrop<[T; N]>, f: &'f mut F) -> Self {
18+
pub(super) const unsafe fn new<const N: usize>(
19+
array: &'l mut ManuallyDrop<[T; N]>,
20+
f: &'f mut F,
21+
) -> Self {
2022
// dont drop the array, transfers "ownership" to Self
2123
let ptr: NonNull<T> = NonNull::from_mut(array).cast();
2224
// SAFETY:
2325
// Adding `slice.len()` to the starting pointer gives a pointer
2426
// at the end of `slice`. `end` will never be dereferenced, only checked
2527
// for direct pointer equality with `ptr` to check if the drainer is done.
2628
unsafe {
27-
let end = if T::IS_ZST { null_mut() } else { ptr.as_ptr().add(N) };
28-
Self { ptr, end, f, l: PhantomData }
29+
let end_or_len =
30+
if T::IS_ZST { without_provenance_mut(N) } else { ptr.as_ptr().add(N) };
31+
Self { ptr, end_or_len, f, l: PhantomData }
2932
}
3033
}
3134
}
3235

3336
/// See [`Drain::new`]; this is our fake iterator.
3437
#[unstable(feature = "array_try_map", issue = "79711")]
35-
pub(super) struct Drain<'l, 'f, T, const N: usize, F> {
36-
// FIXME(const-hack): This is essentially a slice::IterMut<'static>, replace when possible.
38+
pub(super) struct Drain<'l, 'f, T, F> {
39+
// FIXME(const-hack): This is a slice::IterMut<'l>, replace when possible.
3740
/// The pointer to the next element to return, or the past-the-end location
3841
/// if the drainer is empty.
3942
///
4043
/// This address will be used for all ZST elements, never changed.
4144
/// As we "own" this array, we dont need to store any lifetime.
4245
ptr: NonNull<T>,
4346
/// For non-ZSTs, the non-null pointer to the past-the-end element.
44-
/// For ZSTs, this is null.
45-
end: *mut T,
47+
/// For ZSTs, this is the number of unprocessed items.
48+
end_or_len: *mut T,
4649

4750
f: &'f mut F,
48-
l: PhantomData<&'l mut [T; N]>,
51+
l: PhantomData<&'l mut [T]>,
4952
}
5053

5154
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
5255
#[unstable(feature = "array_try_map", issue = "79711")]
53-
impl<T, U, const N: usize, F> const FnOnce<(usize,)> for &mut Drain<'_, '_, T, N, F>
56+
impl<T, U, F> const FnOnce<(usize,)> for &mut Drain<'_, '_, T, F>
5457
where
5558
F: [const] FnMut(T) -> U,
5659
{
@@ -63,7 +66,7 @@ where
6366
}
6467
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
6568
#[unstable(feature = "array_try_map", issue = "79711")]
66-
impl<T, U, const N: usize, F> const FnMut<(usize,)> for &mut Drain<'_, '_, T, N, F>
69+
impl<T, U, F> const FnMut<(usize,)> for &mut Drain<'_, '_, T, F>
6770
where
6871
F: [const] FnMut(T) -> U,
6972
{
@@ -73,6 +76,16 @@ where
7376
(_ /* ignore argument */,): (usize,),
7477
) -> Self::Output {
7578
if T::IS_ZST {
79+
#[expect(ptr_to_integer_transmute_in_consts)]
80+
// SAFETY:
81+
// This is equivalent to `self.end_or_len.addr`, but that's not
82+
// available in `const`. `self.end_or_len` doesn't have provenance,
83+
// so transmuting is fine.
84+
let len = unsafe { transmute::<*mut T, usize>(self.end_or_len) };
85+
// SAFETY:
86+
// The caller guarantees that this is never called more than N times
87+
// (see `Drain::new`), hence this cannot underflow.
88+
self.end_or_len = without_provenance_mut(unsafe { len.unchecked_sub(1) });
7689
// its UB to call this more than N times, so returning more ZSTs is valid.
7790
// SAFETY: its a ZST? we conjur.
7891
(self.f)(unsafe { conjure_zst::<T>() })
@@ -88,20 +101,32 @@ where
88101
}
89102
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
90103
#[unstable(feature = "array_try_map", issue = "79711")]
91-
impl<T: [const] Destruct, const N: usize, F> const Drop for Drain<'_, '_, T, N, F> {
104+
impl<T: [const] Destruct, F> const Drop for Drain<'_, '_, T, F> {
92105
fn drop(&mut self) {
93-
if !T::IS_ZST {
106+
let slice = if T::IS_ZST {
107+
from_raw_parts_mut::<[T]>(
108+
self.ptr.as_ptr(),
109+
#[expect(ptr_to_integer_transmute_in_consts)]
110+
// SAFETY:
111+
// This is equivalent to `self.end_or_len.addr`, but that's not
112+
// available in `const`. `self.end_or_len` doesn't have provenance,
113+
// so transmuting is fine.
114+
unsafe {
115+
transmute::<*mut T, usize>(self.end_or_len)
116+
},
117+
)
118+
} else {
94119
// SAFETY: we cant read more than N elements
95-
let slice = unsafe {
120+
unsafe {
96121
from_raw_parts_mut::<[T]>(
97122
self.ptr.as_ptr(),
98123
// SAFETY: `start <= end`
99-
self.end.offset_from_unsigned(self.ptr.as_ptr()),
124+
self.end_or_len.offset_from_unsigned(self.ptr.as_ptr()),
100125
)
101-
};
126+
}
127+
};
102128

103-
// SAFETY: By the type invariant, we're allowed to drop all these. (we own it, after all)
104-
unsafe { drop_in_place(slice) }
105-
}
129+
// SAFETY: By the type invariant, we're allowed to drop all these. (we own it, after all)
130+
unsafe { drop_in_place(slice) }
106131
}
107132
}

library/coretests/tests/array.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use core::cell::Cell;
12
use core::num::NonZero;
23
use core::sync::atomic::{AtomicUsize, Ordering};
34
use core::{array, assert_eq};
5+
use std::sync::ReentrantLock;
46

57
#[test]
68
fn array_from_ref() {
@@ -718,6 +720,31 @@ fn array_map_drops_unmapped_elements_on_panic() {
718720
}
719721
}
720722

723+
#[cfg(not(panic = "abort"))]
724+
#[test]
725+
fn array_map_drops_unmapped_zst_elements_on_panic() {
726+
static DROPPED: ReentrantLock<Cell<usize>> = ReentrantLock::new(Cell::new(0));
727+
728+
struct ZstDrop;
729+
impl Drop for ZstDrop {
730+
fn drop(&mut self) {
731+
DROPPED.lock().update(|x| x + 1);
732+
}
733+
}
734+
735+
let dropped = DROPPED.lock();
736+
dropped.set(0);
737+
let array = [const { ZstDrop }; 5];
738+
let success = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
739+
let _ = array.map(|x| {
740+
drop(x);
741+
assert_eq!(dropped.get(), 1);
742+
});
743+
}));
744+
assert!(success.is_err());
745+
assert_eq!(dropped.get(), 5);
746+
}
747+
721748
// This covers the `PartialEq::<[T]>::eq` impl for `[T; N]` when it returns false.
722749
#[test]
723750
fn array_eq() {

library/coretests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
#![feature(pointer_is_aligned_to)]
9797
#![feature(portable_simd)]
9898
#![feature(ptr_metadata)]
99+
#![feature(reentrant_lock)]
99100
#![feature(result_option_map_or_default)]
100101
#![feature(rustc_attrs)]
101102
#![feature(signed_bigint_helpers)]

src/librustdoc/clean/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,6 +2780,7 @@ fn add_without_unwanted_attributes<'hir>(
27802780
hir::Attribute::Parsed(AttributeKind::Doc(box d)) => {
27812781
// Remove attributes from `normal` that should not be inherited by `use` re-export.
27822782
let DocAttribute {
2783+
first_span: _,
27832784
aliases,
27842785
hidden,
27852786
inline,

src/librustdoc/json/conversions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,7 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>)
960960
}
961961

962962
let DocAttribute {
963+
first_span: _,
963964
aliases,
964965
hidden,
965966
inline,

0 commit comments

Comments
 (0)