Skip to content

Commit c7b0452

Browse files
committed
Auto merge of #97729 - Dylan-DPC:rollup-dv43xo9, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #96642 (Avoid zero-sized allocs in ThinBox if T and H are both ZSTs.) - #97647 (Lazily allocate and initialize pthread locks.) - #97715 (Support the `#[expect]` attribute on fn parameters (RFC-2383)) - #97716 (Fix reachability analysis for const methods) - #97722 (Tighten spans for bad fields in struct deriving `Copy`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 4a52e0f + 8c4c698 commit c7b0452

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+614
-223
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,15 @@ impl<'a> AstValidator<'a> {
420420
.iter()
421421
.flat_map(|i| i.attrs.as_ref())
422422
.filter(|attr| {
423-
let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
423+
let arr = [
424+
sym::allow,
425+
sym::cfg,
426+
sym::cfg_attr,
427+
sym::deny,
428+
sym::expect,
429+
sym::forbid,
430+
sym::warn,
431+
];
424432
!arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
425433
})
426434
.for_each(|attr| {
@@ -435,7 +443,7 @@ impl<'a> AstValidator<'a> {
435443
} else {
436444
self.err_handler().span_err(
437445
attr.span,
438-
"allow, cfg, cfg_attr, deny, \
446+
"allow, cfg, cfg_attr, deny, expect, \
439447
forbid, and warn are the only allowed built-in attributes in function parameters",
440448
);
441449
}

compiler/rustc_passes/src/reachable.rs

+8-25
Original file line numberDiff line numberDiff line change
@@ -148,32 +148,15 @@ impl<'tcx> ReachableContext<'tcx> {
148148
hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
149149
| hir::TraitItemKind::Type(..) => false,
150150
},
151-
Some(Node::ImplItem(impl_item)) => {
152-
match impl_item.kind {
153-
hir::ImplItemKind::Const(..) => true,
154-
hir::ImplItemKind::Fn(..) => {
155-
let attrs = self.tcx.codegen_fn_attrs(def_id);
156-
let generics = self.tcx.generics_of(def_id);
157-
if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() {
158-
true
159-
} else {
160-
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
161-
let impl_did = self.tcx.hir().get_parent_item(hir_id);
162-
// Check the impl. If the generics on the self
163-
// type of the impl require inlining, this method
164-
// does too.
165-
match self.tcx.hir().expect_item(impl_did).kind {
166-
hir::ItemKind::Impl { .. } => {
167-
let generics = self.tcx.generics_of(impl_did);
168-
generics.requires_monomorphization(self.tcx)
169-
}
170-
_ => false,
171-
}
172-
}
173-
}
174-
hir::ImplItemKind::TyAlias(_) => false,
151+
Some(Node::ImplItem(impl_item)) => match impl_item.kind {
152+
hir::ImplItemKind::Const(..) => true,
153+
hir::ImplItemKind::Fn(..) => {
154+
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
155+
let impl_did = self.tcx.hir().get_parent_item(hir_id);
156+
method_might_be_inlined(self.tcx, impl_item, impl_did)
175157
}
176-
}
158+
hir::ImplItemKind::TyAlias(_) => false,
159+
},
177160
Some(_) => false,
178161
None => false, // This will happen for default methods.
179162
}

compiler/rustc_trait_selection/src/traits/misc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub fn can_type_implement_copy<'tcx>(
2020
tcx: TyCtxt<'tcx>,
2121
param_env: ty::ParamEnv<'tcx>,
2222
self_type: Ty<'tcx>,
23-
cause: ObligationCause<'tcx>,
23+
parent_cause: ObligationCause<'tcx>,
2424
) -> Result<(), CopyImplementationError<'tcx>> {
2525
// FIXME: (@jroesch) float this code up
2626
tcx.infer_ctxt().enter(|infcx| {
@@ -59,7 +59,7 @@ pub fn can_type_implement_copy<'tcx>(
5959
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
6060
.has_param_types_or_consts()
6161
{
62-
cause.clone()
62+
parent_cause.clone()
6363
} else {
6464
ObligationCause::dummy_with_span(span)
6565
};

compiler/rustc_typeck/src/coherence/builtin.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
107107

108108
for (field, ty) in fields {
109109
let field_span = tcx.def_span(field.did);
110+
let field_ty_span = match tcx.hir().get_if_local(field.did) {
111+
Some(hir::Node::Field(field_def)) => field_def.ty.span,
112+
_ => field_span,
113+
};
110114
err.span_label(field_span, "this field does not implement `Copy`");
111115
// Spin up a new FulfillmentContext, so we can get the _precise_ reason
112116
// why this field does not implement Copy. This is useful because sometimes
@@ -119,7 +123,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
119123
param_env,
120124
ty,
121125
tcx.lang_items().copy_trait().unwrap(),
122-
traits::ObligationCause::dummy_with_span(field_span),
126+
traits::ObligationCause::dummy_with_span(field_ty_span),
123127
);
124128
for error in fulfill_cx.select_all_or_error(&infcx) {
125129
let error_predicate = error.obligation.predicate;

library/alloc/src/boxed/thin.rs

+46-19
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,11 @@ impl<T: ?Sized> ThinBox<T> {
138138
}
139139
}
140140

141-
/// A pointer to type-erased data, guaranteed to have a header `H` before the pointed-to location.
141+
/// A pointer to type-erased data, guaranteed to either be:
142+
/// 1. `NonNull::dangling()`, in the case where both the pointee (`T`) and
143+
/// metadata (`H`) are ZSTs.
144+
/// 2. A pointer to a valid `T` that has a header `H` directly before the
145+
/// pointed-to location.
142146
struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
143147

144148
impl<H> WithHeader<H> {
@@ -156,16 +160,27 @@ impl<H> WithHeader<H> {
156160
};
157161

158162
unsafe {
159-
let ptr = alloc::alloc(layout);
160-
161-
if ptr.is_null() {
162-
alloc::handle_alloc_error(layout);
163-
}
164-
// Safety:
165-
// - The size is at least `aligned_header_size`.
166-
let ptr = ptr.add(value_offset) as *mut _;
167-
168-
let ptr = NonNull::new_unchecked(ptr);
163+
// Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
164+
// we use `layout.dangling()` for this case, which should have a valid
165+
// alignment for both `T` and `H`.
166+
let ptr = if layout.size() == 0 {
167+
// Some paranoia checking, mostly so that the ThinBox tests are
168+
// more able to catch issues.
169+
debug_assert!(
170+
value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
171+
);
172+
layout.dangling()
173+
} else {
174+
let ptr = alloc::alloc(layout);
175+
if ptr.is_null() {
176+
alloc::handle_alloc_error(layout);
177+
}
178+
// Safety:
179+
// - The size is at least `aligned_header_size`.
180+
let ptr = ptr.add(value_offset) as *mut _;
181+
182+
NonNull::new_unchecked(ptr)
183+
};
169184

170185
let result = WithHeader(ptr, PhantomData);
171186
ptr::write(result.header(), header);
@@ -175,18 +190,28 @@ impl<H> WithHeader<H> {
175190
}
176191
}
177192

178-
// Safety:
179-
// - Assumes that `value` can be dereferenced.
193+
// Safety:
194+
// - Assumes that either `value` can be dereferenced, or is the
195+
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
180196
unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
181197
unsafe {
198+
let value_layout = Layout::for_value_raw(value);
182199
// SAFETY: Layout must have been computable if we're in drop
183-
let (layout, value_offset) =
184-
Self::alloc_layout(Layout::for_value_raw(value)).unwrap_unchecked();
200+
let (layout, value_offset) = Self::alloc_layout(value_layout).unwrap_unchecked();
185201

186-
ptr::drop_in_place::<T>(value);
187202
// We only drop the value because the Pointee trait requires that the metadata is copy
188-
// aka trivially droppable
189-
alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
203+
// aka trivially droppable.
204+
ptr::drop_in_place::<T>(value);
205+
206+
// Note: Don't deallocate if the layout size is zero, because the pointer
207+
// didn't come from the allocator.
208+
if layout.size() != 0 {
209+
alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
210+
} else {
211+
debug_assert!(
212+
value_offset == 0 && mem::size_of::<H>() == 0 && value_layout.size() == 0
213+
);
214+
}
190215
}
191216
}
192217

@@ -198,7 +223,9 @@ impl<H> WithHeader<H> {
198223
// needed to align the header. Subtracting the header size from the aligned data pointer
199224
// will always result in an aligned header pointer, it just may not point to the
200225
// beginning of the allocation.
201-
unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H }
226+
let hp = unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H };
227+
debug_assert!(hp.is_aligned());
228+
hp
202229
}
203230

204231
fn value(&self) -> *mut u8 {

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
#![feature(nll)] // Not necessary, but here to test the `nll` feature.
170170
#![feature(rustc_allow_const_fn_unstable)]
171171
#![feature(rustc_attrs)]
172+
#![feature(pointer_is_aligned)]
172173
#![feature(slice_internals)]
173174
#![feature(staged_api)]
174175
#![feature(stmt_expr_attributes)]

library/alloc/tests/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
#![feature(panic_update_hook)]
4343
#![feature(slice_flatten)]
4444
#![feature(thin_box)]
45+
#![feature(bench_black_box)]
46+
#![feature(strict_provenance)]
47+
#![feature(once_cell)]
4548

4649
use std::collections::hash_map::DefaultHasher;
4750
use std::hash::{Hash, Hasher};

0 commit comments

Comments
 (0)