diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 32bfa5094c3eb..62da99ac3fb66 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -299,6 +299,12 @@ pub fn from_fn_attrs<'ll, 'tcx>( } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { 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) { // apply to return place instead of function (unlike all other attributes applied in this function) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0ad65e5d99bb4..73cedb59349d3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -191,6 +191,7 @@ pub enum AttributeKind { StackProtect = 32, NoUndef = 33, SanitizeMemTag = 34, + NoCfCheck = 35, } /// LLVMIntPredicate diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index f6a0c19d25953..3f6e8a8f755a1 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -473,6 +473,9 @@ macro_rules! make_value_visitor { // The second `Box` field is the allocator, which we recursively check for validity // like in regular structs. self.visit_field(v, 1, &alloc)?; + + // We visited all parts of this one. + return Ok(()); } _ => {}, }; diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index a2b0e9b4d29d8..9fe84a6309b9c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -84,6 +84,7 @@ enum LLVMRustAttribute { StackProtect = 32, NoUndef = 33, SanitizeMemTag = 34, + NoCfCheck = 35, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 7ac3157e7a1de..2d35ee8976e67 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -176,6 +176,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::NoAlias; case NoCapture: return Attribute::NoCapture; + case NoCfCheck: + return Attribute::NoCfCheck; case NoInline: return Attribute::NoInline; case NonNull: diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 89b376442a887..41c38f558b6ef 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -443,17 +443,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Next, let's construct the error let (error_span, full_call_span, ctor_of) = match &call_expr.kind { hir::ExprKind::Call( - hir::Expr { - span, - kind: - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, - )), - .. - }, + hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, _, - ) => (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::MethodCall(path_segment, _, span) => { let ident_span = path_segment.ident.span; diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 649aeb0890dc0..efdc86bf57a8a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -70,11 +70,14 @@ pub use std::alloc::Global; /// # Examples /// /// ``` -/// use std::alloc::{alloc, dealloc, Layout}; +/// use std::alloc::{alloc, dealloc, handle_alloc_error, Layout}; /// /// unsafe { /// let layout = Layout::new::<u16>(); /// let ptr = alloc(layout); +/// if ptr.is_null() { +/// handle_alloc_error(layout); +/// } /// /// *(ptr as *mut u16) = 42; /// assert_eq!(*(ptr as *mut u16), 42); diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index ecd2b75ae4427..66af491607435 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1040,6 +1040,8 @@ pub fn copy<T: Copy>(x: &T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] 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 align_of::<U>() > align_of::<T>() { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 3b13dc0832fa4..6856d1a1f51ae 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -97,6 +97,46 @@ fn test_transmute_copy() { 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] #[allow(dead_code)] fn test_discriminant_send_sync() { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d6260b8ca06e4..671b40dbfe66d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -57,11 +57,43 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> { .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)), ); items.extend(self.mods.iter().map(|x| x.clean(cx))); - items.extend( - self.items - .iter() - .flat_map(|(item, renamed)| clean_maybe_renamed_item(cx, item, *renamed)), - ); + + // Split up imports from all other items. + // + // 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 // the outer `mod` item for the source code. diff --git a/src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs b/src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs new file mode 100644 index 0000000000000..79b0bb2d7eead --- /dev/null +++ b/src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs @@ -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)) +} diff --git a/src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs b/src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs new file mode 100644 index 0000000000000..bedcded731d95 --- /dev/null +++ b/src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs @@ -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 diff --git a/src/test/codegen/naked-noinline.rs b/src/test/codegen/naked-noinline.rs index 13bc139ecd05a..c0ac69f4ed778 100644 --- a/src/test/codegen/naked-noinline.rs +++ b/src/test/codegen/naked-noinline.rs @@ -28,4 +28,4 @@ pub unsafe fn g() { f(); } -// CHECK: attributes [[ATTR]] = { naked noinline{{.*}} } +// CHECK: attributes [[ATTR]] = { naked{{.*}}noinline{{.*}} } diff --git a/src/test/rustdoc/auxiliary/issue-99221-aux.rs b/src/test/rustdoc/auxiliary/issue-99221-aux.rs new file mode 100644 index 0000000000000..e061e42b29db8 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-99221-aux.rs @@ -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; diff --git a/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs new file mode 100644 index 0000000000000..e74881d387dc1 --- /dev/null +++ b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs @@ -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 { + () => () + } +} diff --git a/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs new file mode 100644 index 0000000000000..46d59654b99eb --- /dev/null +++ b/src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs @@ -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 { + () => () +} diff --git a/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs b/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs new file mode 100644 index 0000000000000..41e64726a3246 --- /dev/null +++ b/src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs @@ -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; diff --git a/src/test/ui/hrtb/issue-95230.rs b/src/test/ui/hrtb/issue-95230.rs new file mode 100644 index 0000000000000..92c506eabb7f4 --- /dev/null +++ b/src/test/ui/hrtb/issue-95230.rs @@ -0,0 +1,7 @@ +// check-pass + +pub struct Bar +where + for<'a> &'a mut Self:; + +fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr index 5467f61bee40f..a922d7a5e4132 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr @@ -7,7 +7,7 @@ LL | fn ts_variant() { LL | Self::TSVariant(()); | --------------- ^^ expected type parameter `T`, found `()` | | - | arguments to this function are incorrect + | arguments to this enum variant are incorrect | = note: expected type parameter `T` found unit type `()` @@ -55,7 +55,7 @@ LL | impl<T> Enum<T> { LL | Self::<()>::TSVariant(()); | --------------------- ^^ expected type parameter `T`, found `()` | | - | arguments to this function are incorrect + | arguments to this enum variant are incorrect | = note: expected type parameter `T` found unit type `()` diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs index d012687533bbe..3a8712f2ae515 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs @@ -18,6 +18,6 @@ impl E2 { } 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 } diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index 6ae2aa1dc774d..006253f843208 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -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 | LL | <E>::V();