rust-lang/rust · #164072

Rollup of 4 pull requests

jhpratt · merged Oct 10, 202611 files · 462 + / 145 −
compiler/rustc_codegen_llvm/src/common.rs1 + / 19 −
@@ -2,7 +2,7 @@  use std::borrow::Borrow; -use libc::{c_char, c_uint};+use libc::c_uint; use rustc_abi::Primitive::Pointer; use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _}; use rustc_ast::Mutability;@@ -511,21 +511,3 @@ pub(crate) fn get_dllimport<'tcx>(     tcx.native_library(id)         .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name)) }--/// Extension trait for explicit casts to `*const c_char`.-pub(crate) trait AsCCharPtr {-    /// Equivalent to `self.as_ptr().cast()`, but only casts to `*const c_char`.-    fn as_c_char_ptr(&self) -> *const c_char;-}--impl AsCCharPtr for str {-    fn as_c_char_ptr(&self) -> *const c_char {-        self.as_ptr().cast()-    }-}--impl AsCCharPtr for [u8] {-    fn as_c_char_ptr(&self) -> *const c_char {-        self.as_ptr().cast()-    }-}
compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs7 + / 3 −
@@ -1,6 +1,6 @@ #![expect(dead_code)] -use libc::{c_char, c_uint};+use libc::{c_char, c_uchar, c_uint};  use super::MetadataKindId; use super::ffi::{AttributeKind, BasicBlock, Context, Metadata, Module, Type, Value};@@ -47,10 +47,14 @@ unsafe extern "C" {     pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;     pub(crate) fn LLVMRustHasFnAttribute(         F: &Value,-        Name: *const c_char,+        Name: *const c_uchar, // See "PTR_LEN_STR".         NameLen: libc::size_t,     ) -> bool;-    pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char, NameLen: libc::size_t);+    pub(crate) fn LLVMRustRemoveFnAttribute(+        F: &Value,+        Name: *const c_uchar, // See "PTR_LEN_STR".+        NameLen: libc::size_t,+    );     pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;     pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;     pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
compiler/rustc_codegen_llvm/src/llvm/ffi.rs15 + / 8 −
@@ -982,7 +982,11 @@ unsafe extern "C" {     // Operations on all values     pub(crate) fn LLVMTypeOf(Val: &Value) -> &Type;     pub(crate) fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;-    pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);+    pub(crate) fn LLVMSetValueName2(+        Val: &Value,+        Name: *const c_uchar, // See "PTR_LEN_STR".+        NameLen: size_t,+    );     pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);     pub(crate) safe fn LLVMGetMetadata<'a>(         Val: &'a Value,@@ -1117,9 +1121,9 @@ unsafe extern "C" {     // Operations on attributes     pub(crate) fn LLVMCreateStringAttribute(         C: &Context,-        Name: *const c_char,+        Name: *const c_uchar, // See "PTR_LEN_STR".         NameLen: c_uint,-        Value: *const c_char,+        Value: *const c_uchar, // See "PTR_LEN_STR".         ValueLen: c_uint,     ) -> &Attribute; @@ -1139,7 +1143,10 @@ unsafe extern "C" {     ) -> &'a Value;      // Operations about llvm intrinsics-    pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint;+    pub(crate) fn LLVMLookupIntrinsicID(+        Name: *const c_uchar, // See "PTR_LEN_STR".+        NameLen: size_t,+    ) -> c_uint;     pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero<c_uint>) -> Bool;     pub(crate) fn LLVMGetIntrinsicDeclaration<'a>(         Mod: &'a Module,@@ -1675,7 +1682,7 @@ unsafe extern "C" {     pub(crate) fn LLVMSetComdat(V: &Value, C: &Comdat);      pub(crate) fn LLVMCreateOperandBundle(-        Tag: *const c_char,+        Tag: *const c_uchar, // See "PTR_LEN_STR".         TagLen: size_t,         Args: *const &'_ Value,         NumArgs: c_uint,@@ -2186,17 +2193,17 @@ unsafe extern "C" {     pub(crate) fn LLVMRustAddModuleFlagU32(         M: &Module,         MergeBehavior: ModuleFlagMergeBehavior,-        Name: *const c_char,+        Name: *const c_uchar, // See "PTR_LEN_STR".         NameLen: size_t,         Value: u32,     );      pub(crate) fn LLVMRustAddModuleFlagString(         M: &Module,         MergeBehavior: ModuleFlagMergeBehavior,-        Name: *const c_char,+        Name: *const c_uchar, // See "PTR_LEN_STR".         NameLen: size_t,-        Value: *const c_char,+        Value: *const c_uchar, // See "PTR_LEN_STR".         ValueLen: size_t,     ); 
compiler/rustc_codegen_llvm/src/llvm/mod.rs17 + / 24 −
@@ -14,7 +14,6 @@ pub(crate) use self::CodeGenOptSize::*; pub(crate) use self::conversions::*; pub(crate) use self::ffi::*; pub(crate) use self::metadata_kind::*;-use crate::common::AsCCharPtr;  mod conversions; pub(crate) mod diagnostic;@@ -46,11 +45,11 @@ pub(crate) fn AddFunctionAttributes<'ll>( }  pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: &str) -> bool {-    unsafe { LLVMRustHasFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }+    unsafe { LLVMRustHasFnAttribute(llfn, name.as_ptr(), name.len()) } }  pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: &str) {-    unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }+    unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_ptr(), name.len()) } }  pub(crate) fn AddCallSiteAttributes<'ll>(@@ -71,9 +70,9 @@ pub(crate) fn CreateAttrStringValue<'ll>(     unsafe {         LLVMCreateStringAttribute(             llcx,-            attr.as_c_char_ptr(),+            attr.as_ptr(),             attr.len().try_into().unwrap(),-            value.as_c_char_ptr(),+            value.as_ptr(),             value.len().try_into().unwrap(),         )     }@@ -83,13 +82,15 @@ pub(crate) fn CreateAttrStringValueFromCStr<'ll>(     attr: &std::ffi::CStr,     value: &std::ffi::CStr, ) -> &'ll Attribute {+    let attr = attr.to_bytes();+    let value = value.to_bytes();     unsafe {         LLVMCreateStringAttribute(             llcx,-            (*attr).as_ptr(),-            (*attr).to_bytes().len() as c_uint,-            (*value).as_ptr(),-            (*value).to_bytes().len() as c_uint,+            attr.as_ptr(),+            attr.len() as c_uint,+            value.as_ptr(),+            value.len() as c_uint,         )     } }@@ -98,7 +99,7 @@ pub(crate) fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attr     unsafe {         LLVMCreateStringAttribute(             llcx,-            attr.as_c_char_ptr(),+            attr.as_ptr(),             attr.len().try_into().unwrap(),             std::ptr::null(),             0,@@ -340,7 +341,7 @@ pub(crate) struct Intrinsic {  impl Intrinsic {     pub(crate) fn lookup(name: &[u8]) -> Option<Self> {-        let id = unsafe { LLVMLookupIntrinsicID(name.as_c_char_ptr(), name.len()) };+        let id = unsafe { LLVMLookupIntrinsicID(name.as_ptr(), name.len()) };         NonZero::new(id).map(|id| Self { id })     } @@ -365,10 +366,7 @@ impl Intrinsic {  /// Safe wrapper for `LLVMSetValueName2` from a byte slice pub(crate) fn set_value_name(value: &Value, name: &[u8]) {-    unsafe {-        let data = name.as_c_char_ptr();-        LLVMSetValueName2(value, data, name.len());-    }+    unsafe { LLVMSetValueName2(value, name.as_ptr(), name.len()) }; }  pub(crate) fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {@@ -408,12 +406,7 @@ pub(crate) struct OperandBundleBox<'a> { impl<'a> OperandBundleBox<'a> {     pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self {         let raw = unsafe {-            LLVMCreateOperandBundle(-                name.as_c_char_ptr(),-                name.len(),-                vals.as_ptr(),-                vals.len() as c_uint,-            )+            LLVMCreateOperandBundle(name.as_ptr(), name.len(), vals.as_ptr(), vals.len() as c_uint)         };         Self { raw: ptr::NonNull::new(raw).unwrap() }     }@@ -444,7 +437,7 @@ pub(crate) fn add_module_flag_u32(     value: u32, ) {     unsafe {-        LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_c_char_ptr(), key.len(), value);+        LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_ptr(), key.len(), value);     } } @@ -458,9 +451,9 @@ pub(crate) fn add_module_flag_str(         LLVMRustAddModuleFlagString(             module,             merge_behavior,-            key.as_c_char_ptr(),+            key.as_ptr(),             key.len(),-            value.as_c_char_ptr(),+            value.as_ptr(),             value.len(),         );     }
compiler/rustc_public/src/abi.rs30 + / 6 −
@@ -100,19 +100,21 @@ pub enum PassMode {     }, } -/// Attributes of a function argument that affect its ABI.-///-/// Not all internal compiler attributes are exposed here, as some are-/// LLVM-specific optimization hints. The internal representation is kept-/// private so it can be expanded in the future.+/// Attributes of a function argument or return value. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub struct ArgAttributes {+    pub(crate) regular: ArgAttributeFlags,     pub(crate) arg_ext: ArgExtension,     pub(crate) pointee_size: Size,     pub(crate) pointee_align: Option<Align>, }  impl ArgAttributes {+    /// Return the calling convention and optimization flags for this argument.+    pub fn regular(&self) -> ArgAttributeFlags {+        self.regular+    }+     /// Return how this argument should be extended when passed in a register.     ///     /// Relevant for integer arguments smaller than the register width.@@ -128,12 +130,34 @@ impl ArgAttributes {         self.pointee_align     } -    /// Return the minimum dereferenceable size of the pointee, if known.+    /// Return the minimum dereferenceable size of the pointee, if it is non-null,+    /// at function entry (for arguments) or return (for return values).+    ///+    /// This alone does not guarantee dereferenceability for the duration of the call.     pub fn pointee_size(&self) -> Size {         self.pointee_size     } } +/// Calling convention and optimization flags for a function argument or return value.+///+/// The capture flags overlap: `captures_none` implies `captures_address`, which+/// implies `captures_read_only`.+#[non_exhaustive]+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]+pub struct ArgAttributeFlags {+    pub captures_none: bool,+    pub captures_address: bool,+    pub captures_read_only: bool,+    pub no_alias: bool,+    pub non_null: bool,+    pub read_only: bool,+    pub in_reg: bool,+    pub no_undef: bool,+    pub writable: bool,+    pub no_free: bool,+}+ /// How a small integer argument should be extended to fill a register. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum ArgExtension {
compiler/rustc_public/src/unstable/convert/stable/abi.rs17 + / 4 −
@@ -10,10 +10,11 @@ use rustc_target::callconv;  use crate::IndexedVal; use crate::abi::{-    AddressSpace, ArgAbi, ArgAttributes, ArgExtension, CallConvention, CastTarget, FieldsShape,-    FloatLength, FnAbi, IndirectMode, IntegerLength, IntegerType, Layout, LayoutShape,-    NumScalableVectors, PassMode, Primitive, Reg, RegKind, ReprFlags, ReprOptions, Scalar,-    TagEncoding, TyAndLayout, Uniform, ValueRepr, VariantFields, VariantsShape, WrappingRange,+    AddressSpace, ArgAbi, ArgAttributeFlags, ArgAttributes, ArgExtension, CallConvention,+    CastTarget, FieldsShape, FloatLength, FnAbi, IndirectMode, IntegerLength, IntegerType, Layout,+    LayoutShape, NumScalableVectors, PassMode, Primitive, Reg, RegKind, ReprFlags, ReprOptions,+    Scalar, TagEncoding, TyAndLayout, Uniform, ValueRepr, VariantFields, VariantsShape,+    WrappingRange, }; use crate::compiler_interface::BridgeTys; use crate::target::MachineSize as Size;@@ -264,6 +265,18 @@ impl<'tcx> Stable<'tcx> for callconv::ArgAttributes {         _: &CompilerCtxt<'cx, BridgeTys>,     ) -> Self::T {         ArgAttributes {+            regular: ArgAttributeFlags {+                captures_none: self.regular.contains(callconv::ArgAttribute::CapturesNone),+                captures_address: self.regular.contains(callconv::ArgAttribute::CapturesAddress),+                captures_read_only: self.regular.contains(callconv::ArgAttribute::CapturesReadOnly),+                no_alias: self.regular.contains(callconv::ArgAttribute::NoAlias),+                non_null: self.regular.contains(callconv::ArgAttribute::NonNull),+                read_only: self.regular.contains(callconv::ArgAttribute::ReadOnly),+                in_reg: self.regular.contains(callconv::ArgAttribute::InReg),+                no_undef: self.regular.contains(callconv::ArgAttribute::NoUndef),+                writable: self.regular.contains(callconv::ArgAttribute::Writable),+                no_free: self.regular.contains(callconv::ArgAttribute::NoFree),+            },             arg_ext: match self.arg_ext {                 callconv::ArgExtension::None => ArgExtension::None,                 callconv::ArgExtension::Zext => ArgExtension::Zext,
compiler/rustc_target/src/callconv/mod.rs3 + / 1 −
@@ -545,7 +545,9 @@ impl<'a, Ty> ArgAbi<'a, Ty> {         // Only integers have signedness         if let BackendRepr::Scalar(scalar) = self.layout.backend_repr             && let Primitive::Int(i, signed) = scalar.primitive()-            && i.size().bits() < bits+            // bools are i1 but their primitive is i8. Unlike other types,+            // bools can be extended to their primitive size.+            && (i.size().bits() < bits || self.layout.backend_repr.is_bool())             && let PassMode::Direct(ref mut attrs) = self.mode         {             if signed {
compiler/rustc_target/src/callconv/x86_64.rs5 + / 0 −
@@ -247,6 +247,11 @@ where                 } else if is_arg || cx.target_spec().is_like_darwin {                     arg.extend_integer_width_to(32);                 }+                // The x86_64 psABI requires bools to be zero-extended to 8-bits, with high bits unspecified.+                // zeroext i1 has this behavior in the LLVM X86 backend.+                if !is_arg && arg.layout.backend_repr.is_bool() {+                    arg.extend_integer_width_to(8);+                }             }         }     };
library/core/src/attribute_docs.rs36 + / 0 −
@@ -194,6 +194,42 @@ const _: () = (); /// [`if`]: ./keyword.if.html const _: () = (); +#[doc(attribute = "crate_name")]+//+/// Specifies the name of the crate.+///+/// Written as an inner attribute at the top of the crate root, `crate_name` is used+/// to specify the name of a crate.+///+/// ```+/// #![crate_name = "my_crate"]+/// ```+///+/// The crate name must not be empty, and must only contain [Unicode alphanumeric] or+/// `_` (U+005F) characters.+///+/// Note that the specified name must match the name given by the `--crate-name` flag.+///+/// ```text+/// error: `--crate-name` and `#[crate_name]` are required to match, but `cli_name` != `attr_name`+///  --> main.rs:1:17+///   |+/// 1 | #![crate_name = "attr_name"]+///   |                 ^^^^^^^^^^^+/// ```+///+/// In a Cargo project the crate name is always passed as `--crate-name`, derived from the target+/// name (`[lib] name` or `[[bin]] name` if set, otherwise `[package] name` for libraries and the+/// primary binary, or the source file name for other binaries). The `crate_name` attribute is+/// therefore redundant here: it adds nothing, and if it is present it must match Cargo's name,+/// otherwise `rustc` reports an error.+///+/// For more information, see the Reference on [the `crate_name` attribute].+///+/// [Unicode alphanumeric]: ../std/primitive.char.html#method.is_alphanumeric+/// [the `crate_name` attribute]: ../reference/crates-and-source-files.html#the-crate_name-attribute+const _: () = ();+ #[doc(attribute = "deny")] // /// Emits an error, preventing the compilation from finishing, when a lint check has failed.
tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs41 + / 21 −
@@ -1,10 +1,12 @@ //@ add-minicore //@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv+//@ revisions:x86_64-linux x86_64-uefi i686 aarch64-apple aarch64-windows aarch64-linux arm riscv -//@[x86_64] compile-flags: --target x86_64-unknown-uefi-//@[x86_64] needs-llvm-components: x86+//@[x86_64-uefi] compile-flags: --target x86_64-unknown-uefi+//@[x86_64-uefi] needs-llvm-components: x86+//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu+//@[x86_64-linux] needs-llvm-components: x86 //@[i686] compile-flags: --target i686-unknown-linux-musl //@[i686] needs-llvm-components: x86 //@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc@@ -33,7 +35,8 @@ use minicore::*; // //                  ZERO/SIGN-EXTENDING TO 32 BITS            NON-EXTENDING //                  ==============================  =======================-// x86_64:          void @c_arg_bool(i1 zeroext %_a)+// x86_64-linux:    void @c_arg_bool(i1 zeroext %_a)+// x86_64-uefi:     void @c_arg_bool(i1 zeroext %_a) // i686:            void @c_arg_bool(i1 zeroext %_a) // aarch64-apple:   void @c_arg_bool(i1 zeroext %_a) // aarch64-windows:                                  void @c_arg_bool(i1 %_a)@@ -43,7 +46,8 @@ use minicore::*; #[no_mangle] pub extern "C" fn c_arg_bool(_a: bool) {} -// x86_64:          void @c_arg_u8(i8 zeroext %_a)+// x86_64-linux:    void @c_arg_u8(i8 zeroext %_a)+// x86_64-uefi:     void @c_arg_u8(i8 zeroext %_a) // i686:            void @c_arg_u8(i8 zeroext %_a) // aarch64-apple:   void @c_arg_u8(i8 zeroext %_a) // aarch64-windows:                                  void @c_arg_u8(i8 %_a)@@ -53,7 +57,8 @@ pub extern "C" fn c_arg_bool(_a: bool) {} #[no_mangle] pub extern "C" fn c_arg_u8(_a: u8) {} -// x86_64:          void @c_arg_u16(i16 zeroext %_a)+// x86_64-linux:    void @c_arg_u16(i16 zeroext %_a)+// x86_64-uefi:     void @c_arg_u16(i16 zeroext %_a) // i686:            void @c_arg_u16(i16 zeroext %_a) // aarch64-apple:   void @c_arg_u16(i16 zeroext %_a) // aarch64-windows:                                 void @c_arg_u16(i16 %_a)@@ -63,7 +68,8 @@ pub extern "C" fn c_arg_u8(_a: u8) {} #[no_mangle] pub extern "C" fn c_arg_u16(_a: u16) {} -// x86_64:          void @c_arg_u32(i32 %_a)+// x86_64-linux:    void @c_arg_u32(i32 %_a)+// x86_64-uefi:     void @c_arg_u32(i32 %_a) // i686:            void @c_arg_u32(i32 %_a) // aarch64-apple:   void @c_arg_u32(i32 %_a) // aarch64-windows:                                 void @c_arg_u32(i32 %_a)@@ -73,7 +79,8 @@ pub extern "C" fn c_arg_u16(_a: u16) {} #[no_mangle] pub extern "C" fn c_arg_u32(_a: u32) {} -// x86_64:          void @c_arg_u64(i64 %_a)+// x86_64-linux:    void @c_arg_u64(i64 %_a)+// x86_64-uefi:     void @c_arg_u64(i64 %_a) // i686:            void @c_arg_u64(i64 %_a) // aarch64-apple:   void @c_arg_u64(i64 %_a) // aarch64-windows:                                 void @c_arg_u64(i64 %_a)@@ -83,7 +90,8 @@ pub extern "C" fn c_arg_u32(_a: u32) {} #[no_mangle] pub extern "C" fn c_arg_u64(_a: u64) {} -// x86_64:          void @c_arg_i8(i8 signext %_a)+// x86_64-linux:    void @c_arg_i8(i8 signext %_a)+// x86_64-uefi:     void @c_arg_i8(i8 signext %_a) // i686:            void @c_arg_i8(i8 signext %_a) // aarch64-apple:   void @c_arg_i8(i8 signext %_a) // aarch64-windows:                                  void @c_arg_i8(i8 %_a)@@ -93,7 +101,8 @@ pub extern "C" fn c_arg_u64(_a: u64) {} #[no_mangle] pub extern "C" fn c_arg_i8(_a: i8) {} -// x86_64:          void @c_arg_i16(i16 signext %_a)+// x86_64-linux:    void @c_arg_i16(i16 signext %_a)+// x86_64-uefi:     void @c_arg_i16(i16 signext %_a) // i686:            void @c_arg_i16(i16 signext %_a) // aarch64-apple:   void @c_arg_i16(i16 signext %_a) // aarch64-windows:                                 void @c_arg_i16(i16 %_a)@@ -103,7 +112,8 @@ pub extern "C" fn c_arg_i8(_a: i8) {} #[no_mangle] pub extern "C" fn c_arg_i16(_a: i16) {} -// x86_64:          void @c_arg_i32(i32 %_a)+// x86_64-linux:    void @c_arg_i32(i32 %_a)+// x86_64-uefi:     void @c_arg_i32(i32 %_a) // i686:            void @c_arg_i32(i32 %_a) // aarch64-apple:   void @c_arg_i32(i32 %_a) // aarch64-windows:                                 void @c_arg_i32(i32 %_a)@@ -113,7 +123,8 @@ pub extern "C" fn c_arg_i16(_a: i16) {} #[no_mangle] pub extern "C" fn c_arg_i32(_a: i32) {} -// x86_64:          void @c_arg_i64(i64 %_a)+// x86_64-linux:    void @c_arg_i64(i64 %_a)+// x86_64-uefi:     void @c_arg_i64(i64 %_a) // i686:            void @c_arg_i64(i64 %_a) // aarch64-apple:   void @c_arg_i64(i64 %_a) // aarch64-windows:                                 void @c_arg_i64(i64 %_a)@@ -123,7 +134,8 @@ pub extern "C" fn c_arg_i32(_a: i32) {} #[no_mangle] pub extern "C" fn c_arg_i64(_a: i64) {} -// x86_64:          zeroext i1 @c_ret_bool()+// x86_64-linux:    zeroext i1 @c_ret_bool()+// x86_64-uefi:     zeroext i1 @c_ret_bool() // i686:            zeroext i1 @c_ret_bool() // aarch64-apple:   zeroext i1 @c_ret_bool() // aarch64-windows:                                 i1 @c_ret_bool()@@ -135,7 +147,8 @@ pub extern "C" fn c_ret_bool() -> bool {     false } -// x86_64:          zeroext i8 @c_ret_u8()+// x86_64-linux:                                    i8 @c_ret_u8()+// x86_64-uefi:     zeroext i8 @c_ret_u8() // i686:            zeroext i8 @c_ret_u8() // aarch64-apple:   zeroext i8 @c_ret_u8() // aarch64-windows:                                 i8 @c_ret_u8()@@ -147,7 +160,8 @@ pub extern "C" fn c_ret_u8() -> u8 {     0 } -// x86_64:          zeroext i16 @c_ret_u16()+// x86_64-linux:                                    i16 @c_ret_u16()+// x86_64-uefi:     zeroext i16 @c_ret_u16() // i686:            zeroext i16 @c_ret_u16() // aarch64-apple:   zeroext i16 @c_ret_u16() // aarch64-windows:                                 i16 @c_ret_u16()@@ -159,7 +173,8 @@ pub extern "C" fn c_ret_u16() -> u16 {     0 } -// x86_64:          i32 @c_ret_u32()+// x86_64-linux:    i32 @c_ret_u32()+// x86_64-uefi:     i32 @c_ret_u32() // i686:            i32 @c_ret_u32() // aarch64-apple:   i32 @c_ret_u32() // aarch64-windows:                                 i32 @c_ret_u32()@@ -171,7 +186,8 @@ pub extern "C" fn c_ret_u32() -> u32 {     0 } -// x86_64:          i64 @c_ret_u64()+// x86_64-linux:    i64 @c_ret_u64()+// x86_64-uefi:     i64 @c_ret_u64() // i686:            i64 @c_ret_u64() // aarch64-apple:   i64 @c_ret_u64() // aarch64-windows:                                 i64 @c_ret_u64()@@ -183,7 +199,8 @@ pub extern "C" fn c_ret_u64() -> u64 {     0 } -// x86_64:          signext i8 @c_ret_i8()+// x86_64-linux:                                    i8 @c_ret_i8()+// x86_64-uefi:     signext i8 @c_ret_i8() // i686:            signext i8 @c_ret_i8() // aarch64-apple:   signext i8 @c_ret_i8() // aarch64-windows:                                 i8 @c_ret_i8()@@ -195,7 +212,8 @@ pub extern "C" fn c_ret_i8() -> i8 {     0 } -// x86_64:          signext i16 @c_ret_i16()+// x86_64-linux:                                    i16 @c_ret_i16()+// x86_64-uefi:     signext i16 @c_ret_i16() // i686:            signext i16 @c_ret_i16() // aarch64-apple:   signext i16 @c_ret_i16() // aarch64-windows:                                 i16 @c_ret_i16()@@ -207,7 +225,8 @@ pub extern "C" fn c_ret_i16() -> i16 {     0 } -// x86_64:          i32 @c_ret_i32()+// x86_64-linux:    i32 @c_ret_i32()+// x86_64-uefi:     i32 @c_ret_i32() // i686:            i32 @c_ret_i32() // aarch64-apple:   i32 @c_ret_i32() // aarch64-windows:                                 i32 @c_ret_i32()@@ -219,7 +238,8 @@ pub extern "C" fn c_ret_i32() -> i32 {     0 } -// x86_64:          i64 @c_ret_i64()+// x86_64-linux:    i64 @c_ret_i64()+// x86_64-uefi:     i64 @c_ret_i64() // i686:            i64 @c_ret_i64() // aarch64-apple:   i64 @c_ret_i64() // aarch64-windows:                                 i64 @c_ret_i64()
tests/ui-fulldeps/rustc_public/check_abi.rs290 + / 59 −
@@ -13,6 +13,7 @@ extern crate rustc_interface; extern crate rustc_middle; #[macro_use] extern crate rustc_public;+extern crate rustc_target;  use std::assert_matches; use std::collections::HashSet;@@ -34,51 +35,244 @@ const CRATE_NAME: &str = "input";  /// This function uses the Stable MIR APIs to get information about the test crate. fn test_stable_mir() -> ControlFlow<()> {+    check_regular_attributes();+     // Find items in the local crate.     let items = rustc_public::all_local_items();      // Test fn_abi-    let target_fn = *get_item(&items, (ItemKind::Fn, "input::fn_abi")).unwrap();-    let instance = Instance::try_from(target_fn).unwrap();-    let fn_abi = instance.fn_abi().unwrap();-    assert_eq!(fn_abi.conv, CallConvention::Rust);-    assert_eq!(fn_abi.args.len(), 3);+    let target_fn =+        *get_item(&items, (ItemKind::Fn, "input::fn_abi")).expect("Expected fn_abi function");+    let instance = Instance::try_from(target_fn).expect("Expected fn_abi instance");+    let fn_abi = instance.fn_abi().expect("Expected function ABI");+    assert_eq!(fn_abi.conv, CallConvention::Rust, "Expected Rust calling convention for fn_abi");+    assert_eq!(fn_abi.args.len(), 3, "Expected three arguments for fn_abi");      check_ignore(&fn_abi.args[0]);     check_primitive(&fn_abi.args[1]);     check_niche(&fn_abi.args[2]);     check_result(&fn_abi.ret);      // Test variadic function.-    let variadic_fn = *get_item(&items, (ItemKind::Fn, "input::variadic_fn")).unwrap();+    let variadic_fn = *get_item(&items, (ItemKind::Fn, "input::variadic_fn"))+        .expect("Expected variadic_fn function");     check_variadic(variadic_fn);      // Extract function pointers.-    let fn_ptr_holder = *get_item(&items, (ItemKind::Fn, "input::fn_ptr_holder")).unwrap();-    let fn_ptr_holder_instance = Instance::try_from(fn_ptr_holder).unwrap();-    let body = fn_ptr_holder_instance.body().unwrap();+    let fn_ptr_holder = *get_item(&items, (ItemKind::Fn, "input::fn_ptr_holder"))+        .expect("Expected fn_ptr_holder function");+    let fn_ptr_holder_instance =+        Instance::try_from(fn_ptr_holder).expect("Expected fn_ptr_holder instance");+    let body = fn_ptr_holder_instance.body().expect("Expected fn_ptr_holder body");     let args = body.arg_locals();      // Test fn_abi of function pointer version.-    let ptr_fn_abi = args[0].ty.kind().fn_sig().unwrap().fn_ptr_abi().unwrap();-    assert_eq!(ptr_fn_abi, fn_abi);+    let ptr_fn_abi = args[0]+        .ty+        .kind()+        .fn_sig()+        .expect("Expected ComplexFn signature")+        .fn_ptr_abi()+        .expect("Expected ComplexFn ABI");+    assert_eq!(ptr_fn_abi, fn_abi, "Expected matching function and function pointer ABIs");      // Test variadic_fn of function pointer version.-    let ptr_variadic_fn_abi = args[1].ty.kind().fn_sig().unwrap().fn_ptr_abi().unwrap();-    assert!(ptr_variadic_fn_abi.c_variadic);-    assert_eq!(ptr_variadic_fn_abi.args.len(), 1);--    let entry = rustc_public::entry_fn().unwrap();-    let main_fn = Instance::try_from(entry).unwrap();+    let ptr_variadic_fn_abi = args[1]+        .ty+        .kind()+        .fn_sig()+        .expect("Expected VariadicFn signature")+        .fn_ptr_abi()+        .expect("Expected VariadicFn ABI");+    assert!(ptr_variadic_fn_abi.c_variadic, "Expected C variadic function pointer");+    assert_eq!(ptr_variadic_fn_abi.args.len(), 1, "Expected one fixed variadic pointer argument");++    let entry = rustc_public::entry_fn().expect("Expected main function");+    let main_fn = Instance::try_from(entry).expect("Expected main instance");     let mut visitor = AdtDefVisitor::default();-    visitor.visit_body(&main_fn.body().unwrap());+    visitor.visit_body(&main_fn.body().expect("Expected main body"));     let AdtDefVisitor { adt_defs } = visitor;-    assert_eq!(adt_defs.len(), 1);+    assert_eq!(adt_defs.len(), 1, "Expected one ADT in main");      // Test ADT representation options-    let repr_c_struct = adt_defs.iter().find(|def| def.trimmed_name() == "ReprCStruct").unwrap();-    assert!(repr_c_struct.repr().flags.is_c);+    let repr_c_struct = adt_defs+        .iter()+        .find(|def| def.trimmed_name() == "ReprCStruct")+        .expect("Expected ReprCStruct definition");+    assert!(repr_c_struct.repr().flags.is_c, "Expected repr(C) for ReprCStruct");++    ControlFlow::Continue(())+}++fn check_regular_attributes() {+    use rustc_target::callconv::{ArgAttribute, ArgAttributes};++    let flags = [+        ArgAttribute::CapturesNone,+        ArgAttribute::CapturesAddress,+        ArgAttribute::CapturesReadOnly,+        ArgAttribute::NoAlias,+        ArgAttribute::NonNull,+        ArgAttribute::ReadOnly,+        ArgAttribute::InReg,+        ArgAttribute::NoUndef,+        ArgAttribute::Writable,+        ArgAttribute::NoFree,+    ];+    for regular in [ArgAttribute::empty(), ArgAttribute::all()].iter().copied().chain(flags) {+        let attrs = rustc_public::rustc_internal::stable(ArgAttributes::from(regular)).regular();+        for (flag, actual) in flags.iter().copied().zip([+            attrs.captures_none,+            attrs.captures_address,+            attrs.captures_read_only,+            attrs.no_alias,+            attrs.non_null,+            attrs.read_only,+            attrs.in_reg,+            attrs.no_undef,+            attrs.writable,+            attrs.no_free,+        ]) {+            assert_eq!(actual, regular.contains(flag), "Expected {flag:?} for {regular:?}");+        }+    }+}++struct ExpectedArgAttributes {+    no_alias: bool,+    non_null: bool,+    read_only: bool,+    no_free: bool,+    pointee_size: usize,+} +fn check_args(args: &[ArgAbi], expected: &[(&str, ExpectedArgAttributes)]) {+    assert_eq!(args.len(), expected.len(), "Expected one set of attributes per argument");+    for (arg, (name, expected)) in args.iter().zip(expected) {+        let PassMode::Direct(attrs) = &arg.mode else {+            panic!("Expected PassMode::Direct for {name}, got: {:?}", arg.mode);+        };+        let regular = attrs.regular();+        assert_eq!(regular.no_alias, expected.no_alias, "Expected no_alias for {name}");+        assert_eq!(regular.non_null, expected.non_null, "Expected non_null for {name}");+        assert_eq!(regular.read_only, expected.read_only, "Expected read_only for {name}");+        assert_eq!(regular.no_free, expected.no_free, "Expected no_free for {name}");+        assert_eq!(+            attrs.pointee_size().bytes(),+            expected.pointee_size,+            "Expected pointee_size for {name}",+        );+        assert!(regular.no_undef, "Expected no_undef for {}", name);+        assert_eq!(+            regular.captures_read_only,+            expected.read_only,+            "Expected captures_read_only for {name}",+        );+        assert!(!regular.captures_none, "Expected captures_none to be unset for {}", name);+        assert!(!regular.captures_address, "Expected captures_address to be unset for {}", name);+    }+}++fn test_pointer_attributes() -> ControlFlow<()> {+    let items = rustc_public::all_local_items();+    let target_fn = get_item(&items, (ItemKind::Fn, "input::pointer_attributes"))+        .expect("Expected pointer_attributes function");+    // Use the signature to exclude attributes deduced from the body.+    let abi = target_fn+        .ty()+        .kind()+        .fn_sig()+        .expect("Expected pointer_attributes signature")+        .fn_ptr_abi()+        .expect("Expected pointer_attributes ABI");+    assert_eq!(abi.args.len(), 6, "Expected six arguments for pointer_attributes");++    check_args(+        &abi.args[..4],+        &[+            (+                "shared",+                ExpectedArgAttributes {+                    no_alias: true,+                    non_null: true,+                    read_only: true,+                    no_free: true,+                    pointee_size: 4,+                },+            ),+            (+                "cell",+                ExpectedArgAttributes {+                    no_alias: false,+                    non_null: true,+                    read_only: false,+                    no_free: false,+                    pointee_size: 0,+                },+            ),+            (+                "raw",+                ExpectedArgAttributes {+                    no_alias: false,+                    non_null: false,+                    read_only: false,+                    no_free: false,+                    pointee_size: 0,+                },+            ),+            (+                "nullable",+                ExpectedArgAttributes {+                    no_alias: true,+                    non_null: false,+                    read_only: true,+                    no_free: true,+                    pointee_size: 4,+                },+            ),+        ],+    );++    let PassMode::Pair(data, len) = &abi.args[4].mode else {+        panic!("Expected PassMode::Pair for slice, got: {:?}", abi.args[4].mode);+    };+    assert!(data.regular().non_null, "Expected non_null for slice data");+    assert!(data.regular().no_free, "Expected no_free for slice data");+    assert!(data.regular().no_alias, "Expected no_alias for slice data");+    assert!(data.regular().read_only, "Expected read_only for slice data");+    assert!(data.regular().captures_read_only, "Expected captures_read_only for slice data");+    assert!(len.regular().no_undef, "Expected no_undef for slice length");+    assert!(!len.regular().non_null, "Expected non_null to be unset for slice length");++    let PassMode::Indirect { attrs, .. } = &abi.args[5].mode else {+        panic!("Expected PassMode::Indirect for indirect, got: {:?}", abi.args[5].mode);+    };+    let regular = attrs.regular();+    assert!(regular.no_alias, "Expected no_alias for indirect");+    assert!(regular.non_null, "Expected non_null for indirect");+    assert!(regular.no_undef, "Expected no_undef for indirect");+    assert!(regular.no_free, "Expected no_free for indirect");+    assert!(!regular.captures_none, "Expected captures_none to be unset for indirect");+    assert!(regular.captures_address, "Expected captures_address for indirect");+    assert!(regular.captures_read_only, "Expected captures_read_only for indirect");+    assert_eq!(attrs.pointee_size().bytes(), 256, "Expected pointee_size for indirect");++    let PassMode::Direct(attrs) = &abi.ret.mode else {+        panic!("Expected PassMode::Direct for return value, got: {:?}", abi.ret.mode);+    };+    let regular = attrs.regular();+    assert!(regular.non_null, "Expected non_null for return value");+    assert!(regular.no_undef, "Expected no_undef for return value");+    assert!(!regular.no_alias, "Expected no_alias to be unset for return value");+    assert!(!regular.read_only, "Expected read_only to be unset for return value");+    assert!(!regular.no_free, "Expected no_free to be unset for return value");+    assert!(!regular.captures_none, "Expected captures_none to be unset for return value");+    assert!(!regular.captures_address, "Expected captures_address to be unset for return value");+    assert!(+        !regular.captures_read_only,+        "Expected captures_read_only to be unset for return value"+    );+    assert_eq!(attrs.pointee_size().bytes(), 4, "Expected pointee_size for return value");     ControlFlow::Continue(()) } @@ -89,74 +283,98 @@ fn test_stable_mir() -> ControlFlow<()> { /// } /// ``` fn check_variadic(variadic_fn: CrateItem) {-    let instance = Instance::try_from(variadic_fn).unwrap();-    let abi = instance.fn_abi().unwrap();-    assert!(abi.c_variadic);-    assert_eq!(abi.args.len(), 1);+    let instance = Instance::try_from(variadic_fn).expect("Expected variadic_fn instance");+    let abi = instance.fn_abi().expect("Expected function ABI");+    assert!(abi.c_variadic, "Expected C variadic function");+    assert_eq!(abi.args.len(), 1, "Expected one fixed variadic argument"); }  /// Check the argument to be ignored: `ignore: [u8; 0]`. fn check_ignore(abi: &ArgAbi) {-    assert!(abi.ty.kind().is_array());-    assert_eq!(abi.mode, PassMode::Ignore);+    assert!(abi.ty.kind().is_array(), "Expected array argument");+    assert_eq!(abi.mode, PassMode::Ignore, "Expected PassMode::Ignore for empty array");     let layout = abi.layout.shape();-    assert!(layout.is_sized());-    assert!(layout.is_1zst());+    assert!(layout.is_sized(), "Expected sized layout for empty array");+    assert!(layout.is_1zst(), "Expected empty array to be a 1-ZST"); }  /// Check the primitive argument: `primitive: char`. fn check_primitive(abi: &ArgAbi) {-    assert!(abi.ty.kind().is_char());+    assert!(abi.ty.kind().is_char(), "Expected char argument");     let PassMode::Direct(ref attrs) = abi.mode else {         panic!("Expected PassMode::Direct for char, got: {:?}", abi.mode);     };     // A char (32-bit) doesn't need sign/zero extension on most platforms.     #[cfg(not(any(target_arch = "loongarch64", target_arch = "riscv64")))]-    assert_eq!(attrs.arg_extension(), ArgExtension::None);+    assert_eq!(attrs.arg_extension(), ArgExtension::None, "Expected no extension for char");     // However, LoongArch64 and RiscV64 ABIs require that 32-bit integers     // (signed or unsigned) are sign-extended when passed in registers.     #[cfg(any(target_arch = "loongarch64", target_arch = "riscv64"))]-    assert_eq!(attrs.arg_extension(), ArgExtension::Sext);+    assert_eq!(attrs.arg_extension(), ArgExtension::Sext, "Expected sign extension for char");     // Direct arguments are not pointers, so no pointee alignment.-    assert_eq!(attrs.pointee_align(), None);+    assert_eq!(attrs.pointee_align(), None, "Expected no pointee alignment for char");     let layout = abi.layout.shape();-    assert!(layout.is_sized());-    assert!(!layout.is_1zst());-    assert_matches!(layout.fields, FieldsShape::Primitive);+    assert!(layout.is_sized(), "Expected sized layout for char");+    assert!(!layout.is_1zst(), "Expected char not to be a 1-ZST");+    assert_matches!(layout.fields, FieldsShape::Primitive, "Expected primitive fields for char"); }  /// Check the return value: `Result<usize, &str>`. fn check_result(abi: &ArgAbi) {-    assert!(abi.ty.kind().is_enum());+    assert!(abi.ty.kind().is_enum(), "Expected Result enum");     let PassMode::Indirect { ref attrs, address_space: _, mode } = abi.mode else {         panic!("Expected PassMode::Indirect for Result, got: {:?}", abi.mode);     };     // Indirect arguments have a pointee alignment (the pointer must be aligned).-    assert!(attrs.pointee_align().is_some());-    assert!(mode == IndirectMode::Pointer);+    assert!(attrs.pointee_align().is_some(), "Expected pointee alignment for Result");+    assert_eq!(mode, IndirectMode::Pointer, "Expected indirect pointer for Result");     let layout = abi.layout.shape();-    assert!(layout.is_sized());-    assert_matches!(layout.fields, FieldsShape::Arbitrary { .. });-    assert_matches!(layout.variants, VariantsShape::Multiple { .. })+    assert!(layout.is_sized(), "Expected sized layout for Result");+    assert_matches!(+        layout.fields,+        FieldsShape::Arbitrary { .. },+        "Expected arbitrary fields for Result",+    );+    assert_matches!(+        layout.variants,+        VariantsShape::Multiple { .. },+        "Expected multiple variants for Result",+    ); }  /// Checks the niche information about `NonZero<u8>`. fn check_niche(abi: &ArgAbi) {-    assert!(abi.ty.kind().is_struct());-    assert_matches!(abi.mode, PassMode::Direct { .. });+    assert!(abi.ty.kind().is_struct(), "Expected NonZero<u8> struct");+    assert_matches!(abi.mode, PassMode::Direct { .. }, "Expected PassMode::Direct for NonZero<u8>");     let layout = abi.layout.shape();-    assert!(layout.is_sized());-    assert_eq!(layout.size.bytes(), 1);--    let ValueRepr::Scalar(scalar) = layout.value_repr else { unreachable!() };-    assert!(scalar.has_niche(&MachineInfo::target()), "Opps: {:?}", scalar);--    let Scalar::Initialized { value, valid_range } = scalar else { unreachable!() };-    assert_matches!(value, Primitive::Int { length: IntegerLength::I8, signed: false });-    assert_eq!(valid_range.start, 1);-    assert_eq!(valid_range.end, u8::MAX.into());-    assert!(!valid_range.contains(0));-    assert!(!valid_range.wraps_around());+    assert!(layout.is_sized(), "Expected sized layout for NonZero<u8>");+    assert_eq!(layout.size.bytes(), 1, "Expected one-byte size for NonZero<u8>");++    let ValueRepr::Scalar(scalar) = layout.value_repr else {+        panic!("Expected scalar representation for NonZero<u8>, got: {:?}", layout.value_repr);+    };+    assert!(+        scalar.has_niche(&MachineInfo::target()),+        "Expected niche for NonZero<u8>, got: {:?}",+        scalar,+    );++    let Scalar::Initialized { value, valid_range } = scalar else {+        panic!("Expected initialized scalar for NonZero<u8>, got: {:?}", scalar);+    };+    assert_matches!(+        value,+        Primitive::Int { length: IntegerLength::I8, signed: false },+        "Expected u8 scalar for NonZero<u8>",+    );+    assert_eq!(valid_range.start, 1, "Expected valid range to start at one for NonZero<u8>");+    assert_eq!(+        valid_range.end,+        u8::MAX.into(),+        "Expected valid range to end at u8::MAX for NonZero<u8>"+    );+    assert!(!valid_range.contains(0), "Expected zero outside valid range for NonZero<u8>");+    assert!(!valid_range.wraps_around(), "Expected non-wrapping valid range for NonZero<u8>"); }  fn get_item<'a>(@@ -186,15 +404,17 @@ impl MirVisitor for AdtDefVisitor { /// it will run the compiler. fn main() {     let path = "alloc_input.rs";-    generate_input(&path).unwrap();-    let args = &[+    generate_input(&path).expect("Expected input file to be generated");+    let mut args = vec![         "rustc".to_string(),         "-Cpanic=abort".to_string(),         "--crate-name".to_string(),         CRATE_NAME.to_string(),         path.to_string(),     ];-    run!(args, test_stable_mir).unwrap();+    run!(&args, test_stable_mir).expect("Expected ABI checks to succeed");+    args.push("-Copt-level=1".to_string());+    run!(&args, test_pointer_attributes).expect("Expected pointer attribute checks to succeed"); }  fn generate_input(path: &str) -> std::io::Result<()> {@@ -215,6 +435,17 @@ fn generate_input(path: &str) -> std::io::Result<()> {                 todo!()         }} +        pub fn pointer_attributes<'a>(+            shared: &'a u32,+            cell: &std::cell::Cell<u32>,+            raw: *const u32,+            nullable: Option<&u32>,+            slice: &[u32],+            indirect: [u64; 32],+        ) -> &'a u32 {{+            shared+        }}+         pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{             0         }}