From 5f5ca889589c24a12864329c027db431adbc7fae Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sun, 3 Jul 2022 10:38:49 +0100 Subject: [PATCH 1/8] Add size assert in transmute_copy --- library/core/src/mem/mod.rs | 2 ++ library/core/tests/mem.rs | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) 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(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(src: &T) -> U { + assert!(size_of::() >= size_of::(), "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::() > align_of::() { // 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() { From 92174f988b0cde631ffac0dbcc9f8fca413d566e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 6 Jul 2022 19:07:52 -0700 Subject: [PATCH 2/8] Stop emitting CET prologues for naked functions We can apply nocf_check as a hack for now. --- compiler/rustc_codegen_llvm/src/attributes.rs | 4 ++++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + .../rustc_llvm/llvm-wrapper/LLVMWrapper.h | 1 + .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 ++ .../assembly/x86_64-naked-fn-no-cet-prolog.rs | 24 +++++++++++++++++++ src/test/codegen/naked-noinline.rs | 2 +- 6 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 9394d60134f8c..8c72f7dc06f25 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -299,6 +299,10 @@ 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)); } 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 5ebc2d6139fc8..2c8e804fff581 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_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 8c5b4e2dc96f9..c4a2f6d0640e1 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/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{{.*}} } From 530b5da49b822fd65214ecbe85455114e0ce725f Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 6 Jul 2022 19:09:33 -0700 Subject: [PATCH 3/8] Also stop emitting BTI prologues for naked functions Same idea but for AArch64. --- compiler/rustc_codegen_llvm/src/attributes.rs | 2 ++ .../aarch64-naked-fn-no-bti-prolog.rs | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 8c72f7dc06f25..c51c8391fa5a4 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -303,6 +303,8 @@ pub fn from_fn_attrs<'ll, 'tcx>( // 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/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)) +} From 080a53a9533de30c614f37d006985c2f26fd30e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Jul 2022 20:43:04 -0400 Subject: [PATCH 4/8] add missing null ptr check in alloc example --- library/alloc/src/alloc.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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::(); /// let ptr = alloc(layout); +/// if ptr.is_null() { +/// handle_alloc_error(layout); +/// } /// /// *(ptr as *mut u16) = 42; /// assert_eq!(*(ptr as *mut u16), 42); From 75a1b1cf066b36decf39f4d5036c0b1aae53c680 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 16 Jul 2022 22:03:13 +0000 Subject: [PATCH 5/8] Use typeck_results to get accurate qpath res for arg mismatch error --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 20 +++++++++---------- .../enum-variant-generic-args.stderr | 4 ++-- ...ant-priority-higher-than-other-inherent.rs | 2 +- ...priority-higher-than-other-inherent.stderr | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) 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/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 Enum { 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() { - ::V(); //~ ERROR this function takes 1 argument but 0 arguments were supplied + ::V(); //~ ERROR this enum variant takes 1 argument but 0 arguments were supplied let _: u8 = ::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 | ::V(); From c8221830c780a7b82e328e9762c1c2f9756e63c0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 16 Jul 2022 12:51:51 -0700 Subject: [PATCH 6/8] rustdoc: avoid inlining items with duplicate `(type, name)` Fixes #99221 --- src/librustdoc/clean/mod.rs | 42 ++++++++++++++++--- src/test/rustdoc/auxiliary/issue-99221-aux.rs | 20 +++++++++ ...tiple-macro-rules-w-same-name-submodule.rs | 19 +++++++++ ...-99221-multiple-macro-rules-w-same-name.rs | 17 ++++++++ ...ssue-99221-multiple-structs-w-same-name.rs | 14 +++++++ 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/test/rustdoc/auxiliary/issue-99221-aux.rs create mode 100644 src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name-submodule.rs create mode 100644 src/test/rustdoc/issue-99221-multiple-macro-rules-w-same-name.rs create mode 100644 src/test/rustdoc/issue-99221-multiple-structs-w-same-name.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2c98cba90d718..25d224b9a7337 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/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; From e6be52bbbde9043385ecc5a4e2460fa85daba9c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 10:47:34 -0400 Subject: [PATCH 7/8] interpret/visitor: add missing early return --- compiler/rustc_const_eval/src/interpret/visitor.rs | 3 +++ 1 file changed, 3 insertions(+) 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(()); } _ => {}, }; From 5172a2f5ce0df276525c2e7b8d09024fda6fc8cd Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 18 Jul 2022 10:15:09 +0900 Subject: [PATCH 8/8] Add regression test for #95230 Signed-off-by: Yuki Okushi --- src/test/ui/hrtb/issue-95230.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/test/ui/hrtb/issue-95230.rs 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() {}