diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 7f65982c550a9..59cc852d7a324 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2145,21 +2145,22 @@ pub enum PointerKind { } /// Encodes extra information we have about a pointer. +/// /// Note that this information is advisory only, and backends are free to ignore it: /// if the information is wrong, that can cause UB, but if the information is absent, /// that must always be okay. #[derive(Copy, Clone, Debug)] pub struct PointeeInfo { - /// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to - /// be reliable. + /// If this is `None`, then this is a raw pointer. pub safe: Option, - /// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes. + /// If `size` is not zero, then the pointer is either null or dereferenceable for this many bytes + /// (independent of `safe`). + /// /// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration /// of this function call", i.e. it is UB for the memory that this pointer points to be freed /// while this function is still running. - /// The size can be zero if the pointer is not dereferenceable. pub size: Size, - /// If `safe` is `Some`, then the pointer is aligned as indicated. + /// The pointer is guaranteed to be aligned this much (independent of `safe`). pub align: Align, } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e4865ece63b6c..4f483cdc5d6c7 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -10,7 +10,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv as _}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -924,19 +924,26 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: count, }) => { let dst = codegen_operand(fx, dst); - let pointee = dst - .layout() - .pointee_info_at(fx, rustc_abi::Size::ZERO) - .expect("Expected pointer"); + + let &ty::RawPtr(pointee, _) = dst.layout().ty.kind() else { + bug!("expected pointer") + }; + let pointee_layout = fx + .tcx + .layout_of(fx.typing_env().as_query_input(pointee)) + .expect("expected pointee to have a layout"); + let elem_size: u64 = pointee_layout.layout.size().bytes(); + let dst = dst.load_scalar(fx); let src = codegen_operand(fx, src).load_scalar(fx); let count = codegen_operand(fx, count).load_scalar(fx); - let elem_size: u64 = pointee.size.bytes(); + let bytes = if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count }; + fx.bcx.call_memcpy(fx.target_config, dst, src, bytes); } }, diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 68fca5a17ad34..48d1b01639099 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -288,7 +288,9 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { Float(f) => cx.type_from_float(f), Pointer(address_space) => { // If we know the alignment, pick something better than i8. - let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { + let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) + && pointee.align > rustc_abi::Align::ONE + { cx.type_pointee_for_align(pointee.align) } else { cx.type_i8() diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 16c9d557d6b65..4e191d6f2f33f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -714,7 +714,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } if let Some(pointee) = layout.pointee_info_at(bx, offset) - && let Some(_) = pointee.safe + && pointee.align > Align::ONE { bx.align_metadata(load, pointee.align); } diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index d0121f7643800..bc3ffa24d5289 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,5 +1,5 @@ use rustc_middle::mir::{self, NonDivergingIntrinsic, StmtDebugInfo}; -use rustc_middle::span_bug; +use rustc_middle::{bug, span_bug, ty}; use tracing::instrument; use super::{FunctionCx, LocalRef}; @@ -77,15 +77,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let dst_val = self.codegen_operand(bx, dst); let src_val = self.codegen_operand(bx, src); let count = self.codegen_operand(bx, count).immediate(); - let pointee_layout = dst_val - .layout - .pointee_info_at(bx, rustc_abi::Size::ZERO) - .expect("Expected pointer"); - let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes())); - let align = pointee_layout.align; + let &ty::RawPtr(pointee, _) = dst_val.layout.ty.kind() else { + bug!("expected pointer") + }; + let pointee_layout = bx + .tcx() + .layout_of(bx.typing_env().as_query_input(pointee)) + .expect("expected pointee to have a layout"); + let elem_size = pointee_layout.layout.size().bytes(); + let bytes = bx.mul(count, bx.const_usize(elem_size)); + + let align = pointee_layout.layout.align.abi; let dst = dst_val.immediate(); let src = src_val.immediate(); + bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty(), None); } mir::StatementKind::FakeRead(..) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 9ec681c374574..80f0af9d663cb 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -341,7 +341,8 @@ language_item_table! { PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1); - ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct, GenericRequirement::None; + ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct, GenericRequirement::Exact(1); + MaybeDangling, sym::maybe_dangling, maybe_dangling, Target::Struct, GenericRequirement::Exact(1); BikeshedGuaranteedNoDrop, sym::bikeshed_guaranteed_no_drop, bikeshed_guaranteed_no_drop, Target::Trait, GenericRequirement::Exact(0); MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None; diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index c141eb0311dcf..8feca4a9bd028 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -62,6 +62,8 @@ bitflags::bitflags! { const IS_PIN_PROJECT = 1 << 12; /// Indicates whether the type is `FieldRepresentingType`. const IS_FIELD_REPRESENTING_TYPE = 1 << 13; + /// Indicates whether the type is `MaybeDangling<_>`. + const IS_MAYBE_DANGLING = 1 << 14; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -373,6 +375,9 @@ impl AdtDefData { if tcx.is_lang_item(did, LangItem::ManuallyDrop) { flags |= AdtFlags::IS_MANUALLY_DROP; } + if tcx.is_lang_item(did, LangItem::MaybeDangling) { + flags |= AdtFlags::IS_MAYBE_DANGLING; + } if tcx.is_lang_item(did, LangItem::UnsafeCell) { flags |= AdtFlags::IS_UNSAFE_CELL; } @@ -500,6 +505,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } + /// Returns `true` if this is `MaybeDangling`. + #[inline] + pub fn is_maybe_dangling(self) -> bool { + self.flags().contains(AdtFlags::IS_MAYBE_DANGLING) + } + /// Returns `true` if this is `Pin`. #[inline] pub fn is_pin(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0dcbafed3e900..915566c088868 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1022,41 +1022,80 @@ where let tcx = cx.tcx(); let typing_env = cx.typing_env(); + // Use conservative pointer kind if not optimizing. This saves us the + // Freeze/Unpin queries, and can save time in the codegen backend (noalias + // attributes in LLVM have compile-time cost even in unoptimized builds). + let optimize = tcx.sess.opts.optimize != OptLevel::No; + let pointee_info = match *this.ty.kind() { - ty::RawPtr(p_ty, _) if offset.bytes() == 0 => { - tcx.layout_of(typing_env.as_query_input(p_ty)).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, - }) + ty::RawPtr(_, _) | ty::FnPtr(..) if offset.bytes() == 0 => { + Some(PointeeInfo { safe: None, size: Size::ZERO, align: Align::ONE }) } - ty::FnPtr(..) if offset.bytes() == 0 => { - tcx.layout_of(typing_env.as_query_input(this.ty)).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, + ty::Ref(_, ty, mt) if offset.bytes() == 0 => { + tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| { + let (size, kind); + match mt { + hir::Mutability::Not => { + let frozen = optimize && ty.is_freeze(tcx, typing_env); + + // Non-frozen shared references are not necessarily dereferenceable for the entire duration of the function + // (see ) + // (if we had "dereferenceable on entry", we could support this) + size = if frozen { layout.size } else { Size::ZERO }; + + kind = PointerKind::SharedRef { frozen }; + } + hir::Mutability::Mut => { + let unpin = optimize + && ty.is_unpin(tcx, typing_env) + && ty.is_unsafe_unpin(tcx, typing_env); + + // Mutable references to potentially self-referential types are not + // necessarily dereferenceable for the entire duration of the function + // (see ) + // (if we had "dereferenceable on entry", we could support this) + size = if unpin { layout.size } else { Size::ZERO }; + + kind = PointerKind::MutableRef { unpin }; + } + }; + PointeeInfo { safe: Some(kind), size, align: layout.align.abi } }) } - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - // Use conservative pointer kind if not optimizing. This saves us the - // Freeze/Unpin queries, and can save time in the codegen backend (noalias - // attributes in LLVM have compile-time cost even in unoptimized builds). - let optimize = tcx.sess.opts.optimize != OptLevel::No; - let kind = match mt { - hir::Mutability::Not => { - PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) } - } - hir::Mutability::Mut => PointerKind::MutableRef { + + ty::Adt(..) + if offset.bytes() == 0 + && let Some(pointee) = this.ty.boxed_ty() => + { + tcx.layout_of(typing_env.as_query_input(pointee)).ok().map(|layout| PointeeInfo { + safe: Some(PointerKind::Box { + // Same logic as for mutable references above. unpin: optimize - && ty.is_unpin(tcx, typing_env) - && ty.is_unsafe_unpin(tcx, typing_env), - }, - }; + && pointee.is_unpin(tcx, typing_env) + && pointee.is_unsafe_unpin(tcx, typing_env), + global: this.ty.is_box_global(tcx), + }), + + // `Box` are not necessarily dereferenceable for the entire duration of the function as + // they can be deallocated at any time. + // (if we had "dereferenceable on entry", we could support this) + size: Size::ZERO, - tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo { - size: layout.size, align: layout.align.abi, - safe: Some(kind), + }) + } + + ty::Adt(adt_def, ..) if adt_def.is_maybe_dangling() => { + Self::ty_and_layout_pointee_info_at(this.field(cx, 0), cx, offset).map(|info| { + PointeeInfo { + // Mark the pointer as raw + // (thus removing noalias/readonly/etc in case of the llvm backend) + safe: None, + // Make sure we don't assert dereferenceability of the pointer. + size: Size::ZERO, + // Preserve the alignment assertion! That is required even inside `MaybeDangling`. + align: info.align, + } }) } @@ -1098,7 +1137,7 @@ where } } Variants::Multiple { .. } => None, - _ => Some(this), + Variants::Empty | Variants::Single { .. } => Some(this), }; if let Some(variant) = data_variant @@ -1135,24 +1174,6 @@ where } } - // Fixup info for the first field of a `Box`. Recursive traversal will have found - // the raw pointer, so size and align are set to the boxed type, but `pointee.safe` - // will still be `None`. - if let Some(ref mut pointee) = result { - if offset.bytes() == 0 - && let Some(boxed_ty) = this.ty.boxed_ty() - { - debug_assert!(pointee.safe.is_none()); - let optimize = tcx.sess.opts.optimize != OptLevel::No; - pointee.safe = Some(PointerKind::Box { - unpin: optimize - && boxed_ty.is_unpin(tcx, typing_env) - && boxed_ty.is_unsafe_unpin(tcx, typing_env), - global: this.ty.is_box_global(tcx), - }); - } - } - result } }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9a2d68fc6639f..6d36ba999a2f4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1230,6 +1230,7 @@ symbols! { maxnumf128, may_dangle, may_unwind, + maybe_dangling, maybe_uninit, maybe_uninit_uninit, maybe_uninit_zeroed, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 07e9b731d21ac..30dc56b543f8f 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,7 +1,7 @@ use std::iter; use rustc_abi::Primitive::Pointer; -use rustc_abi::{BackendRepr, ExternAbi, PointerKind, Scalar, Size}; +use rustc_abi::{Align, BackendRepr, ExternAbi, PointerKind, Scalar, Size}; use rustc_data_structures::assert_matches; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; @@ -269,7 +269,15 @@ fn fn_abi_of_instance<'tcx>( ) } -// Handle safe Rust thin and wide pointers. +/// Returns argument attributes for a scalar argument. +/// +/// `drop_target_pointee`, if set, causes the scalar to be treated like a mutable reference to the +/// given type. This is used to special-case the argument of `ptr::drop_in_place`, interpreting it +/// as `&mut T` instead of `*mut T`, for the purposes of attributes (which is valid as per its +/// safety contract). If `drop_target_pointee` is set, `offset` must be 0 and `layout.ty` must be a +/// pointer to the given type. Note that for wide pointers this function is called twice -- once +/// for the data pointer and once for the vtable pointer. `drop_target_pointee` must only be set +/// for the data pointer. fn arg_attrs_for_rust_scalar<'tcx>( cx: LayoutCx<'tcx>, scalar: Scalar, @@ -302,42 +310,31 @@ fn arg_attrs_for_rust_scalar<'tcx>( let tcx = cx.tcx(); - if let Some(pointee) = layout.pointee_info_at(&cx, offset) { - let kind = if let Some(kind) = pointee.safe { - Some(kind) - } else if let Some(pointee) = drop_target_pointee { - assert_eq!(pointee, layout.ty.builtin_deref(true).unwrap()); - assert_eq!(offset, Size::ZERO); - // The argument to `drop_in_place` is semantically equivalent to a mutable reference. - let mutref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, pointee); - let layout = cx.layout_of(mutref).unwrap(); - layout.pointee_info_at(&cx, offset).and_then(|pi| pi.safe) - } else { - None - }; - if let Some(kind) = kind { + let drop_target_pointee_info = drop_target_pointee.and_then(|pointee| { + assert_eq!(pointee, layout.ty.builtin_deref(true).unwrap()); + assert_eq!(offset, Size::ZERO); + // The argument to `drop_in_place` is semantically equivalent to a mutable reference. + let mutref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, pointee); + let layout = cx.layout_of(mutref).unwrap(); + layout.pointee_info_at(&cx, offset) + }); + + if let Some(pointee) = drop_target_pointee_info.or_else(|| layout.pointee_info_at(&cx, offset)) + { + if pointee.align > Align::ONE { attrs.pointee_align = Some(pointee.align.min(cx.tcx().sess.target.max_reliable_alignment())); + } - attrs.pointee_size = match kind { - // LLVM dereferenceable attribute has unclear semantics on the return type, - // they seem to be "dereferenceable until the end of the program", which is - // generally, not valid for references. See - // - _ if is_return => Size::ZERO, - // `Box` are not necessarily dereferenceable for the entire duration of the function as - // they can be deallocated at any time. Same for non-frozen shared references (see - // ), and for mutable references to - // potentially self-referential types (see - // ). If LLVM had a way - // to say "dereferenceable on entry" we could use it here. - PointerKind::Box { .. } - | PointerKind::SharedRef { frozen: false } - | PointerKind::MutableRef { unpin: false } => Size::ZERO, - PointerKind::SharedRef { frozen: true } - | PointerKind::MutableRef { unpin: true } => pointee.size, - }; + // LLVM dereferenceable attribute has unclear semantics on the return type, + // they seem to be "dereferenceable until the end of the program", which is + // generally, not valid for references. See + // + if !is_return { + attrs.pointee_size = pointee.size; + }; + if let Some(kind) = pointee.safe { // The aliasing rules for `Box` are still not decided, but currently we emit // `noalias` for it. This can be turned off using an unstable flag. // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 @@ -554,7 +551,16 @@ fn fn_abi_new_uncached<'tcx>( }; Ok(ArgAbi::new(cx, layout, |scalar, offset| { - arg_attrs_for_rust_scalar(*cx, scalar, layout, offset, is_return, drop_target_pointee) + arg_attrs_for_rust_scalar( + *cx, + scalar, + layout, + offset, + is_return, + // Only set `drop_target_pointee` for the data part of a wide pointer. + // See `arg_attrs_for_rust_scalar` docs for more information. + drop_target_pointee.filter(|_| offset == Size::ZERO), + ) })) }; diff --git a/library/core/src/mem/maybe_dangling.rs b/library/core/src/mem/maybe_dangling.rs index a5f77e667f975..c85576b5778cc 100644 --- a/library/core/src/mem/maybe_dangling.rs +++ b/library/core/src/mem/maybe_dangling.rs @@ -4,10 +4,6 @@ use crate::{mem, ptr}; /// Allows wrapped [references] and [boxes] to dangle. /// -///
-/// This type is not properly implemented yet, and the documentation below is thus not accurate. -///
-/// /// That is, if a reference (or a `Box`) is wrapped in `MaybeDangling` (including when in a /// (nested) field of a compound type wrapped in `MaybeDangling`), it does not have to follow /// pointer aliasing rules or be dereferenceable. @@ -73,6 +69,7 @@ use crate::{mem, ptr}; #[repr(transparent)] #[rustc_pub_transparent] #[derive(Debug, Copy, Clone, Default)] +#[lang = "maybe_dangling"] pub struct MaybeDangling(P); impl MaybeDangling

{ diff --git a/tests/codegen-llvm/enum/enum-transparent-extract.rs b/tests/codegen-llvm/enum/enum-transparent-extract.rs index 1a05b236abfbb..c54bb3e66e736 100644 --- a/tests/codegen-llvm/enum/enum-transparent-extract.rs +++ b/tests/codegen-llvm/enum/enum-transparent-extract.rs @@ -22,7 +22,7 @@ pub fn make_unmake_result_never(x: i32) -> i32 { #[no_mangle] pub fn extract_control_flow_never(x: ControlFlow<&str, Never>) -> &str { - // CHECK-LABEL: define { ptr, i64 } @extract_control_flow_never(ptr align 1 %x.0, i64 %x.1) + // CHECK-LABEL: define { ptr, i64 } @extract_control_flow_never(ptr %x.0, i64 %x.1) // CHECK: start: // CHECK-NEXT: br label %[[next:bb.*]] // CHECK: [[next]]: diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs index 95edecfc6f79b..80e6ac7bb0f03 100644 --- a/tests/codegen-llvm/function-arguments.rs +++ b/tests/codegen-llvm/function-arguments.rs @@ -185,7 +185,7 @@ pub fn _box(x: Box) -> Box { // With a custom allocator, it should *not* have `noalias`. (See // for why.) The second argument is the allocator, // which is a reference here that still carries `noalias` as usual. -// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %x.1) +// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %x.1) #[no_mangle] pub fn _box_custom(x: Box) { drop(x) @@ -209,14 +209,14 @@ pub fn struct_return() -> S { pub fn helper(_: usize) {} // CHECK: @slice( -// CHECK-SAME: ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, +// CHECK-SAME: ptr noalias noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %_1.0, // CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn slice(_: &[u8]) {} // CHECK: @mutable_slice( -// CHECK-SAME: ptr noalias noundef nonnull align 1 %_1.0, +// CHECK-SAME: ptr noalias noundef nonnull %_1.0, // CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] @@ -234,22 +234,22 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {} pub fn raw_slice(_: *const [u8]) {} // CHECK: @str( -// CHECK-SAME: ptr noalias noundef nonnull readonly align 1{{( captures\(address, read_provenance\))?}} %_1.0, +// CHECK-SAME: ptr noalias noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %_1.0, // CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn str(_: &[u8]) {} -// CHECK: @trait_borrow(ptr noundef nonnull align 1 %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) +// CHECK: @trait_borrow(ptr noundef nonnull %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn trait_borrow(_: &dyn Drop) {} -// CHECK: @option_trait_borrow(ptr noundef align 1 %x.0, ptr %x.1) +// CHECK: @option_trait_borrow(ptr noundef %x.0, ptr %x.1) #[no_mangle] pub fn option_trait_borrow(x: Option<&dyn Drop>) {} -// CHECK: @option_trait_borrow_mut(ptr noundef align 1 %x.0, ptr %x.1) +// CHECK: @option_trait_borrow_mut(ptr noundef %x.0, ptr %x.1) #[no_mangle] pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {} @@ -259,13 +259,13 @@ pub fn trait_raw(_: *const dyn Drop) {} // Ensure that `Box` gets `noalias` when the right traits are present, but removing *either* `Unpin` // or `UnsafeUnpin` is enough to lose the attribute. -// CHECK: @trait_box(ptr noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) +// CHECK: @trait_box(ptr noalias noundef nonnull{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) #[no_mangle] pub fn trait_box(_: Box) {} -// CHECK: @trait_box_pin1(ptr noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) +// CHECK: @trait_box_pin1(ptr noundef nonnull{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) #[no_mangle] pub fn trait_box_pin1(_: Box) {} -// CHECK: @trait_box_pin2(ptr noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) +// CHECK: @trait_box_pin2(ptr noundef nonnull{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) #[no_mangle] pub fn trait_box_pin2(_: Box) {} @@ -281,7 +281,7 @@ pub fn trait_mutref_pin1(_: &mut (i32, dyn Drop + Unpin)) {} #[no_mangle] pub fn trait_mutref_pin2(_: &mut (i32, dyn Drop + UnsafeUnpin)) {} -// CHECK: { ptr, ptr } @trait_option(ptr noalias noundef align 1 %x.0, ptr %x.1) +// CHECK: { ptr, ptr } @trait_option(ptr noalias noundef %x.0, ptr %x.1) #[no_mangle] pub fn trait_option( x: Option>, diff --git a/tests/codegen-llvm/maybe_dangling_refs.rs b/tests/codegen-llvm/maybe_dangling_refs.rs new file mode 100644 index 0000000000000..07493ecac79c5 --- /dev/null +++ b/tests/codegen-llvm/maybe_dangling_refs.rs @@ -0,0 +1,46 @@ +// This test checks for absence of noalias and dereferenceable attributes on +// arguments wrapped in `MaybeDangling`. +// +// This also tests +// +//@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -Cno-prepopulate-passes +#![crate_type = "lib"] +#![feature(maybe_dangling)] + +use std::mem::MaybeDangling; + +// CHECK: define {{(dso_local )?}}noundef nonnull ptr @f(ptr noundef nonnull %x) unnamed_addr +#[no_mangle] +pub fn f(x: MaybeDangling>) -> MaybeDangling> { + x +} + +// CHECK: define {{(dso_local )?}}noundef nonnull ptr @g(ptr noundef nonnull %x) unnamed_addr +#[no_mangle] +pub fn g(x: MaybeDangling<&u8>) -> MaybeDangling<&u8> { + x +} + +// CHECK: define {{(dso_local )?}}noundef nonnull ptr @h(ptr noundef nonnull %x) unnamed_addr +#[no_mangle] +pub fn h(x: MaybeDangling<&mut u8>) -> MaybeDangling<&mut u8> { + x +} + +// CHECK: define {{(dso_local )?}}noundef nonnull align 4 ptr @i(ptr noundef nonnull align 4 %x) unnamed_addr +#[no_mangle] +pub fn i(x: MaybeDangling>) -> MaybeDangling> { + x +} + +// CHECK: define {{(dso_local )?}}noundef nonnull align 4 ptr @j(ptr noundef nonnull align 4 %x) unnamed_addr +#[no_mangle] +pub fn j(x: MaybeDangling<&u32>) -> MaybeDangling<&u32> { + x +} + +// CHECK: define {{(dso_local )?}}noundef nonnull align 4 ptr @k(ptr noundef nonnull align 4 %x) unnamed_addr +#[no_mangle] +pub fn k(x: MaybeDangling<&mut u32>) -> MaybeDangling<&mut u32> { + x +} diff --git a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs index 4510e70cbc350..7d71be8e33d80 100644 --- a/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs +++ b/tests/codegen-llvm/sanitizer/kcfi/emit-type-metadata-trait-objects.rs @@ -76,7 +76,7 @@ impl Trait5 for T { pub fn foo1(a: &dyn Trait1) { a.foo(); // CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] } pub fn bar1() { @@ -84,13 +84,13 @@ pub fn bar1() { let b = &a as &dyn Trait1; b.foo(); // CHECK-LABEL: define{{.*}}4bar1{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] } pub fn foo2(a: &dyn Trait2) { a.bar(); // CHECK-LABEL: define{{.*}}4foo2{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] } pub fn bar2() { @@ -99,14 +99,14 @@ pub fn bar2() { let b = &a as &dyn Trait2; b.bar(); // CHECK-LABEL: define{{.*}}4bar2{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] } pub fn foo3(a: &dyn Trait3) { let b = Type3; a.baz(&b); // CHECK-LABEL: define{{.*}}4foo3{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}, ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] } pub fn bar3() { @@ -115,14 +115,14 @@ pub fn bar3() { let b = &a as &dyn Trait3; b.baz(&a); // CHECK-LABEL: define{{.*}}4bar3{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}, ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] } pub fn foo4<'a>(a: &dyn Trait4<'a, Type4, Output = &'a i32>) { let b = Type4; a.qux(&b); // CHECK-LABEL: define{{.*}}4foo4{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] + // CHECK: call align 4 ptr %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}, ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] } pub fn bar4<'a>() { @@ -131,14 +131,14 @@ pub fn bar4<'a>() { let b = &a as &dyn Trait4<'a, Type4, Output = &'a i32>; b.qux(&a); // CHECK-LABEL: define{{.*}}4bar4{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call align 4 ptr %{{[0-9]}}(ptr align 1 {{%[a-z]\.0|%_[0-9]}}, ptr align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] + // CHECK: call align 4 ptr %{{[0-9]}}(ptr {{%[a-z]\.0|%_[0-9]}}, ptr {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE4:[[:print:]]+]]) ] } pub fn foo5(a: &dyn Trait5) { let b = &[Type5; 32]; a.quux(&b); // CHECK-LABEL: define{{.*}}4foo5{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z](\.0)*|%_[0-9]+]}}, ptr {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] } pub fn bar5() { @@ -147,7 +147,7 @@ pub fn bar5() { let b = &a as &dyn Trait5; b.quux(&a); // CHECK-LABEL: define{{.*}}4bar5{{.*}}!{{|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %{{[0-9]}}(ptr align 1 {{%[a-z](\.0)*|%_[0-9]+]}}, ptr align 1 {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] + // CHECK: call void %{{[0-9]}}(ptr {{%[a-z](\.0)*|%_[0-9]+]}}, ptr {{%[a-z](\.0)*|%_[0-9]+}}){{.*}}[ "kcfi"(i32 [[TYPE5:[[:print:]]+]]) ] } // CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]} diff --git a/tests/codegen-llvm/union-aggregate.rs b/tests/codegen-llvm/union-aggregate.rs index 7faa66804feaa..984e2f5715e50 100644 --- a/tests/codegen-llvm/union-aggregate.rs +++ b/tests/codegen-llvm/union-aggregate.rs @@ -50,7 +50,7 @@ fn make_mu_ref_uninit<'a>() -> MU<&'a u16> { #[no_mangle] fn make_mu_str(x: &str) -> MU<&str> { - // CHECK-LABEL: { ptr, i64 } @make_mu_str(ptr align 1 %x.0, i64 %x.1) + // CHECK-LABEL: { ptr, i64 } @make_mu_str(ptr %x.0, i64 %x.1) // CHECK-NEXT: start: // CHECK-NEXT: %0 = insertvalue { ptr, i64 } poison, ptr %x.0, 0 // CHECK-NEXT: %1 = insertvalue { ptr, i64 } %0, i64 %x.1, 1 diff --git a/tests/codegen-llvm/vtable-upcast.rs b/tests/codegen-llvm/vtable-upcast.rs index 9e13e8dd68ac6..d5e74c6e52ca0 100644 --- a/tests/codegen-llvm/vtable-upcast.rs +++ b/tests/codegen-llvm/vtable-upcast.rs @@ -56,7 +56,7 @@ pub fn upcast_diamond_to_a(x: &dyn Diamond) -> &dyn A { } // CHECK-LABEL: upcast_diamond_to_b -// CHECK-SAME: (ptr align {{[0-9]+}} [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]]) +// CHECK-SAME: (ptr [[DATA_PTR:%.+]], ptr align {{[0-9]+}} [[VTABLE_PTR:%.+]]) #[no_mangle] pub fn upcast_diamond_to_b(x: &dyn Diamond) -> &dyn B { // Requires adjustment, since it's a non-first supertrait.