mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 19:17:43 +00:00
Auto merge of #99422 - Dylan-DPC:rollup-htjofm6, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #98839 (Add assertion that `transmute_copy`'s U is not larger than T) - #98998 (Remove branch target prologues from `#[naked] fn`) - #99198 (add missing null ptr check in alloc example) - #99344 (rustdoc: avoid inlining items with duplicate `(type, name)`) - #99351 (Use `typeck_results` to get accurate qpath res for arg mismatch error) - #99378 (interpret/visitor: add missing early return) - #99394 (Add regression test for #95230) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f8588549c3
@ -299,6 +299,12 @@ pub fn from_fn_attrs<'ll, 'tcx>(
|
|||||||
}
|
}
|
||||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||||
to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
|
to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
|
||||||
|
// HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions.
|
||||||
|
// And it is a module-level attribute, so the alternative is pulling naked functions into new LLVM modules.
|
||||||
|
// Otherwise LLVM's "naked" functions come with endbr prefixes per https://github.com/rust-lang/rust/issues/98768
|
||||||
|
to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx));
|
||||||
|
// Need this for AArch64.
|
||||||
|
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
|
||||||
}
|
}
|
||||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
|
||||||
// apply to return place instead of function (unlike all other attributes applied in this function)
|
// apply to return place instead of function (unlike all other attributes applied in this function)
|
||||||
|
@ -191,6 +191,7 @@ pub enum AttributeKind {
|
|||||||
StackProtect = 32,
|
StackProtect = 32,
|
||||||
NoUndef = 33,
|
NoUndef = 33,
|
||||||
SanitizeMemTag = 34,
|
SanitizeMemTag = 34,
|
||||||
|
NoCfCheck = 35,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LLVMIntPredicate
|
/// LLVMIntPredicate
|
||||||
|
@ -473,6 +473,9 @@ macro_rules! make_value_visitor {
|
|||||||
// The second `Box` field is the allocator, which we recursively check for validity
|
// The second `Box` field is the allocator, which we recursively check for validity
|
||||||
// like in regular structs.
|
// like in regular structs.
|
||||||
self.visit_field(v, 1, &alloc)?;
|
self.visit_field(v, 1, &alloc)?;
|
||||||
|
|
||||||
|
// We visited all parts of this one.
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
|
@ -84,6 +84,7 @@ enum LLVMRustAttribute {
|
|||||||
StackProtect = 32,
|
StackProtect = 32,
|
||||||
NoUndef = 33,
|
NoUndef = 33,
|
||||||
SanitizeMemTag = 34,
|
SanitizeMemTag = 34,
|
||||||
|
NoCfCheck = 35,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct OpaqueRustString *RustStringRef;
|
typedef struct OpaqueRustString *RustStringRef;
|
||||||
|
@ -176,6 +176,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
|
|||||||
return Attribute::NoAlias;
|
return Attribute::NoAlias;
|
||||||
case NoCapture:
|
case NoCapture:
|
||||||
return Attribute::NoCapture;
|
return Attribute::NoCapture;
|
||||||
|
case NoCfCheck:
|
||||||
|
return Attribute::NoCfCheck;
|
||||||
case NoInline:
|
case NoInline:
|
||||||
return Attribute::NoInline;
|
return Attribute::NoInline;
|
||||||
case NonNull:
|
case NonNull:
|
||||||
|
@ -443,17 +443,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Next, let's construct the error
|
// Next, let's construct the error
|
||||||
let (error_span, full_call_span, ctor_of) = match &call_expr.kind {
|
let (error_span, full_call_span, ctor_of) = match &call_expr.kind {
|
||||||
hir::ExprKind::Call(
|
hir::ExprKind::Call(
|
||||||
hir::Expr {
|
hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. },
|
||||||
span,
|
|
||||||
kind:
|
|
||||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
|
||||||
_,
|
|
||||||
hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
|
|
||||||
)),
|
|
||||||
..
|
|
||||||
},
|
|
||||||
_,
|
_,
|
||||||
) => (call_span, *span, Some(of)),
|
) => {
|
||||||
|
if let Res::Def(DefKind::Ctor(of, _), _) =
|
||||||
|
self.typeck_results.borrow().qpath_res(qpath, *hir_id)
|
||||||
|
{
|
||||||
|
(call_span, *span, Some(of))
|
||||||
|
} else {
|
||||||
|
(call_span, *span, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None),
|
hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None),
|
||||||
hir::ExprKind::MethodCall(path_segment, _, span) => {
|
hir::ExprKind::MethodCall(path_segment, _, span) => {
|
||||||
let ident_span = path_segment.ident.span;
|
let ident_span = path_segment.ident.span;
|
||||||
|
@ -70,11 +70,14 @@ pub use std::alloc::Global;
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::alloc::{alloc, dealloc, Layout};
|
/// use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
|
||||||
///
|
///
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// let layout = Layout::new::<u16>();
|
/// let layout = Layout::new::<u16>();
|
||||||
/// let ptr = alloc(layout);
|
/// let ptr = alloc(layout);
|
||||||
|
/// if ptr.is_null() {
|
||||||
|
/// handle_alloc_error(layout);
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// *(ptr as *mut u16) = 42;
|
/// *(ptr as *mut u16) = 42;
|
||||||
/// assert_eq!(*(ptr as *mut u16), 42);
|
/// assert_eq!(*(ptr as *mut u16), 42);
|
||||||
|
@ -1040,6 +1040,8 @@ pub fn copy<T: Copy>(x: &T) -> T {
|
|||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
|
#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
|
||||||
pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||||
|
assert!(size_of::<T>() >= size_of::<U>(), "cannot transmute_copy if U is larger than T");
|
||||||
|
|
||||||
// If U has a higher alignment requirement, src might not be suitably aligned.
|
// If U has a higher alignment requirement, src might not be suitably aligned.
|
||||||
if align_of::<U>() > align_of::<T>() {
|
if align_of::<U>() > align_of::<T>() {
|
||||||
// SAFETY: `src` is a reference which is guaranteed to be valid for reads.
|
// SAFETY: `src` is a reference which is guaranteed to be valid for reads.
|
||||||
|
@ -97,6 +97,46 @@ fn test_transmute_copy() {
|
|||||||
assert_eq!(1, unsafe { transmute_copy(&1) });
|
assert_eq!(1, unsafe { transmute_copy(&1) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transmute_copy_shrink() {
|
||||||
|
assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transmute_copy_unaligned() {
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Unaligned {
|
||||||
|
a: u8,
|
||||||
|
b: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
let u = Unaligned::default();
|
||||||
|
assert_eq!(0_u64, unsafe { transmute_copy(&u.b) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(panic = "unwind")]
|
||||||
|
fn test_transmute_copy_grow_panics() {
|
||||||
|
use std::panic;
|
||||||
|
|
||||||
|
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
|
||||||
|
let _unused: u64 = transmute_copy(&1_u8);
|
||||||
|
}));
|
||||||
|
|
||||||
|
match err {
|
||||||
|
Ok(_) => unreachable!(),
|
||||||
|
Err(payload) => {
|
||||||
|
payload
|
||||||
|
.downcast::<&'static str>()
|
||||||
|
.and_then(|s| {
|
||||||
|
if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(s) }
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|p| panic::resume_unwind(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn test_discriminant_send_sync() {
|
fn test_discriminant_send_sync() {
|
||||||
|
@ -57,11 +57,43 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
|
|||||||
.map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
|
.map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
|
||||||
);
|
);
|
||||||
items.extend(self.mods.iter().map(|x| x.clean(cx)));
|
items.extend(self.mods.iter().map(|x| x.clean(cx)));
|
||||||
items.extend(
|
|
||||||
self.items
|
// Split up imports from all other items.
|
||||||
.iter()
|
//
|
||||||
.flat_map(|(item, renamed)| clean_maybe_renamed_item(cx, item, *renamed)),
|
// This covers the case where somebody does an import which should pull in an item,
|
||||||
);
|
// but there's already an item with the same namespace and same name. Rust gives
|
||||||
|
// priority to the not-imported one, so we should, too.
|
||||||
|
let mut inserted = FxHashSet::default();
|
||||||
|
items.extend(self.items.iter().flat_map(|(item, renamed)| {
|
||||||
|
// First, lower everything other than imports.
|
||||||
|
if matches!(item.kind, hir::ItemKind::Use(..)) {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
let v = clean_maybe_renamed_item(cx, item, *renamed);
|
||||||
|
for item in &v {
|
||||||
|
if let Some(name) = item.name {
|
||||||
|
inserted.insert((item.type_(), name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}));
|
||||||
|
items.extend(self.items.iter().flat_map(|(item, renamed)| {
|
||||||
|
// Now we actually lower the imports, skipping everything else.
|
||||||
|
if !matches!(item.kind, hir::ItemKind::Use(..)) {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
let mut v = clean_maybe_renamed_item(cx, item, *renamed);
|
||||||
|
v.drain_filter(|item| {
|
||||||
|
if let Some(name) = item.name {
|
||||||
|
// If an item with the same type and name already exists,
|
||||||
|
// it takes priority over the inlined stuff.
|
||||||
|
!inserted.insert((item.type_(), name))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
v
|
||||||
|
}));
|
||||||
|
|
||||||
// determine if we should display the inner contents or
|
// determine if we should display the inner contents or
|
||||||
// the outer `mod` item for the source code.
|
// the outer `mod` item for the source code.
|
||||||
|
21
src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs
Normal file
21
src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti
|
||||||
|
// assembly-output: emit-asm
|
||||||
|
// needs-asm-support
|
||||||
|
// only-aarch64
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
use std::arch::asm;
|
||||||
|
|
||||||
|
// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
|
||||||
|
// meaning "no prologue whatsoever, no, really, not one instruction."
|
||||||
|
// Unfortunately, aarch64's "branch target identification" works via hints at landing sites.
|
||||||
|
// LLVM implements this via making sure of that, even for functions with the naked attribute.
|
||||||
|
// So, we must emit an appropriate instruction instead!
|
||||||
|
#[no_mangle]
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "C" fn _hlt() -> ! {
|
||||||
|
// CHECK-NOT: hint #34
|
||||||
|
// CHECK: hlt #0x1
|
||||||
|
asm!("hlt #1", options(noreturn))
|
||||||
|
}
|
24
src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs
Normal file
24
src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// compile-flags: -C no-prepopulate-passes -Zcf-protection=full
|
||||||
|
// assembly-output: emit-asm
|
||||||
|
// needs-asm-support
|
||||||
|
// only-x86_64
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
use std::arch::asm;
|
||||||
|
|
||||||
|
// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
|
||||||
|
// meaning "no prologue whatsoever, no, really, not one instruction."
|
||||||
|
// Unfortunately, x86's control-flow enforcement, specifically indirect branch protection,
|
||||||
|
// works by using an instruction for each possible landing site,
|
||||||
|
// and LLVM implements this via making sure of that.
|
||||||
|
#[no_mangle]
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "sysv64" fn will_halt() -> ! {
|
||||||
|
// CHECK-NOT: endbr{{32|64}}
|
||||||
|
// CHECK: hlt
|
||||||
|
asm!("hlt", options(noreturn))
|
||||||
|
}
|
||||||
|
|
||||||
|
// what about aarch64?
|
||||||
|
// "branch-protection"=false
|
@ -28,4 +28,4 @@ pub unsafe fn g() {
|
|||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: attributes [[ATTR]] = { naked noinline{{.*}} }
|
// CHECK: attributes [[ATTR]] = { naked{{.*}}noinline{{.*}} }
|
||||||
|
20
src/test/rustdoc/auxiliary/issue-99221-aux.rs
Normal file
20
src/test/rustdoc/auxiliary/issue-99221-aux.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
pub struct Option;
|
||||||
|
impl Option {
|
||||||
|
pub fn unwrap(self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod macros {
|
||||||
|
use crate::Option;
|
||||||
|
/// [`Option::unwrap`]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
() => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod structs {
|
||||||
|
use crate::Option;
|
||||||
|
/// [`Option::unwrap`]
|
||||||
|
pub struct Print;
|
||||||
|
}
|
||||||
|
pub use structs::Print;
|
@ -0,0 +1,19 @@
|
|||||||
|
// aux-build:issue-99221-aux.rs
|
||||||
|
// build-aux-docs
|
||||||
|
// ignore-cross-compile
|
||||||
|
|
||||||
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate issue_99221_aux;
|
||||||
|
|
||||||
|
pub use issue_99221_aux::*;
|
||||||
|
|
||||||
|
// @count foo/index.html '//a[@class="macro"]' 1
|
||||||
|
|
||||||
|
mod inner {
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
() => ()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// aux-build:issue-99221-aux.rs
|
||||||
|
// build-aux-docs
|
||||||
|
// ignore-cross-compile
|
||||||
|
|
||||||
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate issue_99221_aux;
|
||||||
|
|
||||||
|
pub use issue_99221_aux::*;
|
||||||
|
|
||||||
|
// @count foo/index.html '//a[@class="macro"]' 1
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
() => ()
|
||||||
|
}
|
14
src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs
Normal file
14
src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// aux-build:issue-99221-aux.rs
|
||||||
|
// build-aux-docs
|
||||||
|
// ignore-cross-compile
|
||||||
|
|
||||||
|
#![crate_name = "foo"]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate issue_99221_aux;
|
||||||
|
|
||||||
|
pub use issue_99221_aux::*;
|
||||||
|
|
||||||
|
// @count foo/index.html '//a[@class="struct"][@title="foo::Print struct"]' 1
|
||||||
|
|
||||||
|
pub struct Print;
|
7
src/test/ui/hrtb/issue-95230.rs
Normal file
7
src/test/ui/hrtb/issue-95230.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
pub struct Bar
|
||||||
|
where
|
||||||
|
for<'a> &'a mut Self:;
|
||||||
|
|
||||||
|
fn main() {}
|
@ -7,7 +7,7 @@ LL | fn ts_variant() {
|
|||||||
LL | Self::TSVariant(());
|
LL | Self::TSVariant(());
|
||||||
| --------------- ^^ expected type parameter `T`, found `()`
|
| --------------- ^^ expected type parameter `T`, found `()`
|
||||||
| |
|
| |
|
||||||
| arguments to this function are incorrect
|
| arguments to this enum variant are incorrect
|
||||||
|
|
|
|
||||||
= note: expected type parameter `T`
|
= note: expected type parameter `T`
|
||||||
found unit type `()`
|
found unit type `()`
|
||||||
@ -55,7 +55,7 @@ LL | impl<T> Enum<T> {
|
|||||||
LL | Self::<()>::TSVariant(());
|
LL | Self::<()>::TSVariant(());
|
||||||
| --------------------- ^^ expected type parameter `T`, found `()`
|
| --------------------- ^^ expected type parameter `T`, found `()`
|
||||||
| |
|
| |
|
||||||
| arguments to this function are incorrect
|
| arguments to this enum variant are incorrect
|
||||||
|
|
|
|
||||||
= note: expected type parameter `T`
|
= note: expected type parameter `T`
|
||||||
found unit type `()`
|
found unit type `()`
|
||||||
|
@ -18,6 +18,6 @@ impl E2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
<E>::V(); //~ ERROR this function takes 1 argument but 0 arguments were supplied
|
<E>::V(); //~ ERROR this enum variant takes 1 argument but 0 arguments were supplied
|
||||||
let _: u8 = <E2>::V; //~ ERROR mismatched types
|
let _: u8 = <E2>::V; //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
error[E0061]: this function takes 1 argument but 0 arguments were supplied
|
error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
|
||||||
--> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5
|
--> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5
|
||||||
|
|
|
|
||||||
LL | <E>::V();
|
LL | <E>::V();
|
||||||
|
Loading…
Reference in New Issue
Block a user