rust-lang/rust · #164072
Rollup of 4 pull requests
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 }}