Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #97727

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,15 @@ impl<'a> AstValidator<'a> {
.iter()
.flat_map(|i| i.attrs.as_ref())
.filter(|attr| {
let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
let arr = [
sym::allow,
sym::cfg,
sym::cfg_attr,
sym::deny,
sym::expect,
sym::forbid,
sym::warn,
];
!arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
})
.for_each(|attr| {
Expand All @@ -435,7 +443,7 @@ impl<'a> AstValidator<'a> {
} else {
self.err_handler().span_err(
attr.span,
"allow, cfg, cfg_attr, deny, \
"allow, cfg, cfg_attr, deny, expect, \
forbid, and warn are the only allowed built-in attributes in function parameters",
);
}
Expand Down
33 changes: 8 additions & 25 deletions compiler/rustc_passes/src/reachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,32 +148,15 @@ impl<'tcx> ReachableContext<'tcx> {
hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
| hir::TraitItemKind::Type(..) => false,
},
Some(Node::ImplItem(impl_item)) => {
match impl_item.kind {
hir::ImplItemKind::Const(..) => true,
hir::ImplItemKind::Fn(..) => {
let attrs = self.tcx.codegen_fn_attrs(def_id);
let generics = self.tcx.generics_of(def_id);
if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() {
true
} else {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let impl_did = self.tcx.hir().get_parent_item(hir_id);
// Check the impl. If the generics on the self
// type of the impl require inlining, this method
// does too.
match self.tcx.hir().expect_item(impl_did).kind {
hir::ItemKind::Impl { .. } => {
let generics = self.tcx.generics_of(impl_did);
generics.requires_monomorphization(self.tcx)
}
_ => false,
}
}
}
hir::ImplItemKind::TyAlias(_) => false,
Some(Node::ImplItem(impl_item)) => match impl_item.kind {
hir::ImplItemKind::Const(..) => true,
hir::ImplItemKind::Fn(..) => {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let impl_did = self.tcx.hir().get_parent_item(hir_id);
method_might_be_inlined(self.tcx, impl_item, impl_did)
}
}
hir::ImplItemKind::TyAlias(_) => false,
},
Some(_) => false,
None => false, // This will happen for default methods.
}
Expand Down
65 changes: 46 additions & 19 deletions library/alloc/src/boxed/thin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ impl<T: ?Sized> ThinBox<T> {
}
}

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

impl<H> WithHeader<H> {
Expand All @@ -156,16 +160,27 @@ impl<H> WithHeader<H> {
};

unsafe {
let ptr = alloc::alloc(layout);

if ptr.is_null() {
alloc::handle_alloc_error(layout);
}
// Safety:
// - The size is at least `aligned_header_size`.
let ptr = ptr.add(value_offset) as *mut _;

let ptr = NonNull::new_unchecked(ptr);
// Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
// we use `layout.dangling()` for this case, which should have a valid
// alignment for both `T` and `H`.
let ptr = if layout.size() == 0 {
// Some paranoia checking, mostly so that the ThinBox tests are
// more able to catch issues.
debug_assert!(
value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
);
layout.dangling()
} else {
let ptr = alloc::alloc(layout);
if ptr.is_null() {
alloc::handle_alloc_error(layout);
}
// Safety:
// - The size is at least `aligned_header_size`.
let ptr = ptr.add(value_offset) as *mut _;

NonNull::new_unchecked(ptr)
};

let result = WithHeader(ptr, PhantomData);
ptr::write(result.header(), header);
Expand All @@ -175,18 +190,28 @@ impl<H> WithHeader<H> {
}
}

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

ptr::drop_in_place::<T>(value);
// We only drop the value because the Pointee trait requires that the metadata is copy
// aka trivially droppable
alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
// aka trivially droppable.
ptr::drop_in_place::<T>(value);

// Note: Don't deallocate if the layout size is zero, because the pointer
// didn't come from the allocator.
if layout.size() != 0 {
alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
} else {
debug_assert!(
value_offset == 0 && mem::size_of::<H>() == 0 && value_layout.size() == 0
);
}
}
}

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

fn value(&self) -> *mut u8 {
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
#![feature(nll)] // Not necessary, but here to test the `nll` feature.
#![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)]
#![feature(pointer_is_aligned)]
#![feature(slice_internals)]
#![feature(staged_api)]
#![feature(stmt_expr_attributes)]
Expand Down
3 changes: 3 additions & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
#![feature(panic_update_hook)]
#![feature(slice_flatten)]
#![feature(thin_box)]
#![feature(bench_black_box)]
#![feature(strict_provenance)]
#![feature(once_cell)]

use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
Expand Down
Loading