| author | bors <bors@rust-lang.org> 2026-06-30 05:19:16 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-30 05:19:16 UTC |
| log | 345632878cffcb4c8e90750e943296b43d16c76e |
| tree | 39a30c218913b717d5e4ea4e80c0d7abb6f83577 |
| parent | 096694416a41840709140eb0fd0ca193d1a3e6ba |
| parent | 977911031effd4c53f0903406fa657c56bef4184 |
Rollup of 11 pull requests
Successful merges:
- rust-lang/rust#155722 (Introduce aarch64-unknown-linux-pauthtest target)
- rust-lang/rust#156230 (tests: check wasm compiler_builtins object architecture)
- rust-lang/rust#156295 (Pass the whole `GenericArgs` to `Interner::for_each_relevant_impl()`)
- rust-lang/rust#158375 (Support `DefKind::InlineConst` in `ConstKind::Unevaluated`)
- rust-lang/rust#158556 (delegation: store child segment flag in `PathSegment`)
- rust-lang/rust#158081 (trait-system: Recover deferred closure calls after errors)
- rust-lang/rust#158468 (Include default-stability info in rustdoc JSON.)
- rust-lang/rust#158543 (Note usage of documentation hard links in `core::io`)
- rust-lang/rust#158564 (fix `-Z min-recursion-limit` unstable chapter name)
- rust-lang/rust#158568 (llvm-wrapper: use accessors for private fields in LLVM 23+)
- rust-lang/rust#158582 (Comment on needed RAM in huge-stacks.rs)110 files changed, 2562 insertions(+), 330 deletions(-)
compiler/rustc_ast_lowering/src/delegation.rs+6-1| ... | ... | @@ -55,7 +55,9 @@ use rustc_span::def_id::{DefId, LocalDefId}; |
| 55 | 55 | use rustc_span::symbol::kw; |
| 56 | 56 | use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; |
| 57 | 57 | |
| 58 | use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults}; | |
| 58 | use crate::delegation::generics::{ | |
| 59 | GenericsGenerationResult, GenericsGenerationResults, GenericsPosition, | |
| 60 | }; | |
| 59 | 61 | use crate::diagnostics::{ |
| 60 | 62 | CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion, |
| 61 | 63 | DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee, |
| ... | ... | @@ -505,6 +507,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 505 | 507 | res: Res::Local(param_id), |
| 506 | 508 | args: None, |
| 507 | 509 | infer_args: false, |
| 510 | delegation_child_segment: false, | |
| 508 | 511 | })); |
| 509 | 512 | |
| 510 | 513 | let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); |
| ... | ... | @@ -714,6 +717,8 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 714 | 717 | result.args_segment_id = segment.hir_id; |
| 715 | 718 | result.use_for_sig_inheritance = !result.generics.is_trait_impl(); |
| 716 | 719 | |
| 720 | segment.delegation_child_segment = result.generics.pos() == GenericsPosition::Child; | |
| 721 | ||
| 717 | 722 | segment |
| 718 | 723 | } |
| 719 | 724 |
compiler/rustc_ast_lowering/src/delegation/generics.rs+10-2| ... | ... | @@ -12,7 +12,7 @@ use rustc_span::{Ident, Span, sym}; |
| 12 | 12 | use crate::LoweringContext; |
| 13 | 13 | use crate::diagnostics::DelegationInfersMismatch; |
| 14 | 14 | |
| 15 | #[derive(Debug, Clone, Copy)] | |
| 15 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | |
| 16 | 16 | pub(super) enum GenericsPosition { |
| 17 | 17 | Parent, |
| 18 | 18 | Child, |
| ... | ... | @@ -155,7 +155,7 @@ impl<'hir> DelegationGenericArgsIterator<'hir> { |
| 155 | 155 | impl<'hir> HirOrTyGenerics<'hir> { |
| 156 | 156 | pub(super) fn into_hir_generics(&mut self, ctx: &mut LoweringContext<'_, 'hir>, span: Span) { |
| 157 | 157 | if let HirOrTyGenerics::Ty(ty) = self { |
| 158 | let rename_self = matches!(ty.pos, GenericsPosition::Child); | |
| 158 | let rename_self = ty.pos == GenericsPosition::Child; | |
| 159 | 159 | let params = ctx.uplift_delegation_generic_params(span, &ty.data, rename_self); |
| 160 | 160 | |
| 161 | 161 | *self = HirOrTyGenerics::Hir(DelegationGenerics { |
| ... | ... | @@ -218,6 +218,13 @@ impl<'hir> HirOrTyGenerics<'hir> { |
| 218 | 218 | .expect("`Self` generic param is not found while expected"), |
| 219 | 219 | } |
| 220 | 220 | } |
| 221 | ||
| 222 | pub(crate) fn pos(&self) -> GenericsPosition { | |
| 223 | match self { | |
| 224 | HirOrTyGenerics::Ty(ty) => ty.pos, | |
| 225 | HirOrTyGenerics::Hir(hir) => hir.pos, | |
| 226 | } | |
| 227 | } | |
| 221 | 228 | } |
| 222 | 229 | |
| 223 | 230 | impl<'hir> GenericsGenerationResult<'hir> { |
| ... | ... | @@ -590,6 +597,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 590 | 597 | ident: p.name.ident(), |
| 591 | 598 | infer_args: false, |
| 592 | 599 | res, |
| 600 | delegation_child_segment: false, | |
| 593 | 601 | }]), |
| 594 | 602 | res, |
| 595 | 603 | span: p.span, |
compiler/rustc_ast_lowering/src/lib.rs+2-1| ... | ... | @@ -1014,6 +1014,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 1014 | 1014 | res, |
| 1015 | 1015 | args, |
| 1016 | 1016 | infer_args: args.is_none(), |
| 1017 | delegation_child_segment: false, | |
| 1017 | 1018 | }]), |
| 1018 | 1019 | }) |
| 1019 | 1020 | } |
| ... | ... | @@ -2791,7 +2792,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 2791 | 2792 | } |
| 2792 | 2793 | ExprKind::ConstBlock(anon_const) => { |
| 2793 | 2794 | let def_id = self.local_def_id(anon_const.id); |
| 2794 | assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id)); | |
| 2795 | assert_eq!(DefKind::InlineConst, self.tcx.def_kind(def_id)); | |
| 2795 | 2796 | self.lower_anon_const_to_const_arg(anon_const, span) |
| 2796 | 2797 | } |
| 2797 | 2798 | _ => overly_complex_const(self), |
compiler/rustc_ast_lowering/src/path.rs+1| ... | ... | @@ -412,6 +412,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 412 | 412 | } else { |
| 413 | 413 | Some(generic_args.into_generic_args(self)) |
| 414 | 414 | }, |
| 415 | delegation_child_segment: false, | |
| 415 | 416 | } |
| 416 | 417 | } |
| 417 | 418 |
compiler/rustc_borrowck/src/universal_regions.rs+1-1| ... | ... | @@ -615,7 +615,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { |
| 615 | 615 | |
| 616 | 616 | BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { |
| 617 | 617 | match tcx.def_kind(self.mir_def) { |
| 618 | DefKind::InlineConst => { | |
| 618 | DefKind::InlineConst if !tcx.is_type_system_inline_const(self.mir_def) => { | |
| 619 | 619 | // This is required for `AscribeUserType` canonical query, which will call |
| 620 | 620 | // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes |
| 621 | 621 | // into borrowck, which is ICE #78174. |
compiler/rustc_codegen_gcc/src/common.rs+10-3| ... | ... | @@ -2,7 +2,8 @@ use gccjit::{LValue, RValue, ToRValue, Type}; |
| 2 | 2 | use rustc_abi::Primitive::Pointer; |
| 3 | 3 | use rustc_abi::{self as abi, HasDataLayout}; |
| 4 | 4 | use rustc_codegen_ssa::traits::{ |
| 5 | BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, | |
| 5 | BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, PacMetadata, | |
| 6 | StaticCodegenMethods, | |
| 6 | 7 | }; |
| 7 | 8 | use rustc_middle::mir::Mutability; |
| 8 | 9 | use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; |
| ... | ... | @@ -241,7 +242,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { |
| 241 | 242 | None |
| 242 | 243 | } |
| 243 | 244 | |
| 244 | fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { | |
| 245 | fn scalar_to_backend_with_pac( | |
| 246 | &self, | |
| 247 | cv: Scalar, | |
| 248 | layout: abi::Scalar, | |
| 249 | ty: Type<'gcc>, | |
| 250 | _pac: Option<PacMetadata>, | |
| 251 | ) -> RValue<'gcc> { | |
| 245 | 252 | let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; |
| 246 | 253 | match cv { |
| 247 | 254 | Scalar::Int(int) => { |
| ... | ... | @@ -290,7 +297,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { |
| 290 | 297 | } |
| 291 | 298 | value |
| 292 | 299 | } |
| 293 | GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), | |
| 300 | GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, None), | |
| 294 | 301 | GlobalAlloc::VTable(ty, dyn_ty) => { |
| 295 | 302 | let alloc = self |
| 296 | 303 | .tcx |
compiler/rustc_codegen_gcc/src/context.rs+4-2| ... | ... | @@ -5,7 +5,9 @@ use gccjit::{Block, CType, Context, Function, FunctionType, LValue, Location, RV |
| 5 | 5 | use rustc_abi::{Align, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; |
| 6 | 6 | use rustc_codegen_ssa::base::wants_msvc_seh; |
| 7 | 7 | use rustc_codegen_ssa::errors as ssa_errors; |
| 8 | use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods}; | |
| 8 | use rustc_codegen_ssa::traits::{ | |
| 9 | BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods, PacMetadata, | |
| 10 | }; | |
| 9 | 11 | use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; |
| 10 | 12 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
| 11 | 13 | use rustc_middle::mir::interpret::Allocation; |
| ... | ... | @@ -398,7 +400,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { |
| 398 | 400 | get_fn(self, instance) |
| 399 | 401 | } |
| 400 | 402 | |
| 401 | fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { | |
| 403 | fn get_fn_addr(&self, instance: Instance<'tcx>, _pac: Option<PacMetadata>) -> RValue<'gcc> { | |
| 402 | 404 | let func_name = self.tcx.symbol_name(instance).name; |
| 403 | 405 | |
| 404 | 406 | let func = if let Some(variable) = self.get_declared_value(func_name) { |
compiler/rustc_codegen_llvm/src/attributes.rs+10-1| ... | ... | @@ -12,9 +12,12 @@ use rustc_session::config::{ |
| 12 | 12 | }; |
| 13 | 13 | use rustc_span::sym; |
| 14 | 14 | use rustc_symbol_mangling::mangle_internal_symbol; |
| 15 | use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector}; | |
| 15 | use rustc_target::spec::{ | |
| 16 | Arch, FramePointer, LlvmAbi, SanitizerSet, StackProbeType, StackProtector, | |
| 17 | }; | |
| 16 | 18 | use smallvec::SmallVec; |
| 17 | 19 | |
| 20 | use crate::common::pauth_fn_attrs; | |
| 18 | 21 | use crate::context::SimpleCx; |
| 19 | 22 | use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; |
| 20 | 23 | use crate::llvm::AttributePlace::Function; |
| ... | ... | @@ -643,6 +646,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( |
| 643 | 646 | } |
| 644 | 647 | } |
| 645 | 648 | |
| 649 | if sess.target.llvm_abiname == LlvmAbi::Pauthtest { | |
| 650 | for &ptrauth_attr in pauth_fn_attrs() { | |
| 651 | to_add.push(llvm::CreateAttrString(cx.llcx, ptrauth_attr)); | |
| 652 | } | |
| 653 | } | |
| 654 | ||
| 646 | 655 | to_add.extend(target_features_attr(cx, tcx, function_features)); |
| 647 | 656 | |
| 648 | 657 | attributes::apply_to_llfn(llfn, Function, &to_add); |
compiler/rustc_codegen_llvm/src/base.rs+38-2| ... | ... | @@ -25,12 +25,13 @@ use rustc_middle::mono::Visibility; |
| 25 | 25 | use rustc_middle::ty::TyCtxt; |
| 26 | 26 | use rustc_session::config::{DebugInfo, Offload}; |
| 27 | 27 | use rustc_span::Symbol; |
| 28 | use rustc_target::spec::SanitizerSet; | |
| 28 | use rustc_target::spec::{LlvmAbi, SanitizerSet}; | |
| 29 | 29 | |
| 30 | 30 | use super::ModuleLlvm; |
| 31 | 31 | use crate::attributes; |
| 32 | 32 | use crate::builder::Builder; |
| 33 | 33 | use crate::builder::gpu_offload::OffloadGlobals; |
| 34 | use crate::common::pauth_fn_attrs; | |
| 34 | 35 | use crate::context::CodegenCx; |
| 35 | 36 | use crate::llvm::{self, Value}; |
| 36 | 37 | |
| ... | ... | @@ -123,7 +124,18 @@ pub(crate) fn compile_codegen_unit( |
| 123 | 124 | if let Some(entry) = |
| 124 | 125 | maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit) |
| 125 | 126 | { |
| 126 | let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerFnAttrs::default()); | |
| 127 | let mut attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerFnAttrs::default()); | |
| 128 | // When pointer authentication is enabled, ensure that the ptrauth-* attributes are | |
| 129 | // also attached to the entry wrapper. | |
| 130 | // | |
| 131 | // FIXME(jchlanda) If it ever becomes necessary to ensure that all compiler | |
| 132 | // generated functions receive the ptrauth-* attributes, `declare_fn` or | |
| 133 | // `declare_raw_fn` could be used to provide those. | |
| 134 | if cx.sess().target.llvm_abiname == LlvmAbi::Pauthtest { | |
| 135 | for &ptrauth_attr in pauth_fn_attrs() { | |
| 136 | attrs.push(llvm::CreateAttrString(cx.llcx, ptrauth_attr)); | |
| 137 | } | |
| 138 | } | |
| 127 | 139 | attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); |
| 128 | 140 | } |
| 129 | 141 | |
| ... | ... | @@ -140,6 +152,30 @@ pub(crate) fn compile_codegen_unit( |
| 140 | 152 | cx.add_objc_module_flags(); |
| 141 | 153 | } |
| 142 | 154 | |
| 155 | if cx.sess().target.llvm_abiname == LlvmAbi::Pauthtest { | |
| 156 | // FIXME(jchlanda): In LLVM/Clang, there are also `aarch64-elf-pauthabi-platform` | |
| 157 | // and `aarch64-elf-pauthabi-version` module flags. These are emitted into the | |
| 158 | // PAuth core info section of the resulting ELF, which the linker uses to enforce | |
| 159 | // binary compatibility. | |
| 160 | // | |
| 161 | // We intentionally do not emit these flags now, since only a subset of features | |
| 162 | // included in clang's pauthtest is currently supported. By default, the absence of | |
| 163 | // this info is treated as compatible with any binary. | |
| 164 | // | |
| 165 | // Please note, that this would cause compatibility issues, specifically runtime | |
| 166 | // crashes due to authentication failures (while compiling and linking | |
| 167 | // successfully) when linking against binaries that support larger set of features | |
| 168 | // (for example, signing of C++ member function pointers, virtual function | |
| 169 | // pointers, virtual table pointers). | |
| 170 | // | |
| 171 | // Link to PAuth core info documentation: | |
| 172 | // <https://github.com/ARM-software/abi-aa/blob/2025Q4/pauthabielf64/pauthabielf64.rst#core-information> | |
| 173 | if cx.sess().opts.unstable_opts.ptrauth_elf_got { | |
| 174 | cx.add_ptrauth_elf_got_flag(); | |
| 175 | } | |
| 176 | cx.add_ptrauth_sign_personality_flag(); | |
| 177 | } | |
| 178 | ||
| 143 | 179 | // Finalize code coverage by injecting the coverage map. Note, the coverage map will |
| 144 | 180 | // also be added to the `llvm.compiler.used` variable, created next. |
| 145 | 181 | if cx.sess().instrument_coverage() { |
compiler/rustc_codegen_llvm/src/builder.rs+51-2| ... | ... | @@ -7,7 +7,7 @@ pub(crate) mod autodiff; |
| 7 | 7 | pub(crate) mod gpu_offload; |
| 8 | 8 | |
| 9 | 9 | use libc::{c_char, c_uint}; |
| 10 | use rustc_abi::{self as abi, Align, Size, WrappingRange}; | |
| 10 | use rustc_abi::{self as abi, Align, CanonAbi, Size, WrappingRange}; | |
| 11 | 11 | use rustc_codegen_ssa::MemFlags; |
| 12 | 12 | use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind}; |
| 13 | 13 | use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; |
| ... | ... | @@ -26,7 +26,7 @@ use rustc_sanitizers::{cfi, kcfi}; |
| 26 | 26 | use rustc_session::config::OptLevel; |
| 27 | 27 | use rustc_span::Span; |
| 28 | 28 | use rustc_target::callconv::{FnAbi, PassMode}; |
| 29 | use rustc_target::spec::{Arch, HasTargetSpec, SanitizerSet, Target}; | |
| 29 | use rustc_target::spec::{Arch, HasTargetSpec, LlvmAbi, SanitizerSet, Target}; | |
| 30 | 30 | use smallvec::SmallVec; |
| 31 | 31 | use tracing::{debug, instrument}; |
| 32 | 32 | |
| ... | ... | @@ -475,6 +475,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { |
| 475 | 475 | bundles.push(kcfi_bundle); |
| 476 | 476 | } |
| 477 | 477 | |
| 478 | let pauth = self.ptrauth_operand_bundle(llfn, fn_abi); | |
| 479 | if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) { | |
| 480 | bundles.push(p); | |
| 481 | } | |
| 482 | ||
| 478 | 483 | let invoke = unsafe { |
| 479 | 484 | llvm::LLVMBuildInvokeWithOperandBundles( |
| 480 | 485 | self.llbuilder, |
| ... | ... | @@ -1472,6 +1477,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { |
| 1472 | 1477 | bundles.push(kcfi_bundle); |
| 1473 | 1478 | } |
| 1474 | 1479 | |
| 1480 | let pauth = self.ptrauth_operand_bundle(llfn, fn_abi); | |
| 1481 | if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) { | |
| 1482 | bundles.push(p); | |
| 1483 | } | |
| 1484 | ||
| 1475 | 1485 | let call = unsafe { |
| 1476 | 1486 | llvm::LLVMBuildCallWithOperandBundles( |
| 1477 | 1487 | self.llbuilder, |
| ... | ... | @@ -1902,6 +1912,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { |
| 1902 | 1912 | bundles.push(kcfi_bundle); |
| 1903 | 1913 | } |
| 1904 | 1914 | |
| 1915 | let pauth = self.ptrauth_operand_bundle(llfn, fn_abi); | |
| 1916 | if let Some(p) = pauth.as_ref().map(|b| b.as_ref()) { | |
| 1917 | bundles.push(p); | |
| 1918 | } | |
| 1919 | ||
| 1905 | 1920 | let callbr = unsafe { |
| 1906 | 1921 | llvm::LLVMBuildCallBr( |
| 1907 | 1922 | self.llbuilder, |
| ... | ... | @@ -2021,6 +2036,40 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { |
| 2021 | 2036 | kcfi_bundle |
| 2022 | 2037 | } |
| 2023 | 2038 | |
| 2039 | // Emits pauth operand bundle. | |
| 2040 | fn ptrauth_operand_bundle( | |
| 2041 | &mut self, | |
| 2042 | llfn: &'ll Value, | |
| 2043 | fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, | |
| 2044 | ) -> Option<llvm::OperandBundleBox<'ll>> { | |
| 2045 | if self.sess().target.llvm_abiname != LlvmAbi::Pauthtest { | |
| 2046 | return None; | |
| 2047 | } | |
| 2048 | // Pointer authentication support is currently limited to extern "C" calls; filter out other | |
| 2049 | // ABIs. | |
| 2050 | if fn_abi?.conv != CanonAbi::C { | |
| 2051 | return None; | |
| 2052 | } | |
| 2053 | // Filter out LLVM intrinsics. | |
| 2054 | if llvm::get_value_name(llfn).starts_with(b"llvm.") { | |
| 2055 | return None; | |
| 2056 | } | |
| 2057 | ||
| 2058 | // FIXME(jchlanda) Operand bundles should only be attached to indirect function calls. | |
| 2059 | // However, function pointer signing is currently performed in `get_fn_addr`, which causes | |
| 2060 | // the logic to be applied too broadly, including to function values (not just pointers). | |
| 2061 | // As a result, direct calls using signed function values must also receive operand | |
| 2062 | // bundles. | |
| 2063 | // Once this is resolved, we should analyze each call and skip direct calls. See the | |
| 2064 | // discussion in the rust-lang issue: <https://github.com/rust-lang/rust/issues/152532> | |
| 2065 | let key: u32 = 0; | |
| 2066 | let discriminator: u64 = 0; | |
| 2067 | Some(llvm::OperandBundleBox::new( | |
| 2068 | "ptrauth", | |
| 2069 | &[self.const_u32(key), self.const_u64(discriminator)], | |
| 2070 | )) | |
| 2071 | } | |
| 2072 | ||
| 2024 | 2073 | /// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation. |
| 2025 | 2074 | #[instrument(level = "debug", skip(self))] |
| 2026 | 2075 | pub(crate) fn instrprof_increment( |
compiler/rustc_codegen_llvm/src/common.rs+82-9| ... | ... | @@ -4,23 +4,81 @@ use std::borrow::Borrow; |
| 4 | 4 | |
| 5 | 5 | use libc::{c_char, c_uint}; |
| 6 | 6 | use rustc_abi::Primitive::Pointer; |
| 7 | use rustc_abi::{self as abi, HasDataLayout as _}; | |
| 7 | use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _}; | |
| 8 | 8 | use rustc_ast::Mutability; |
| 9 | 9 | use rustc_codegen_ssa::common::TypeKind; |
| 10 | 10 | use rustc_codegen_ssa::traits::*; |
| 11 | 11 | use rustc_data_structures::stable_hash::{StableHash, StableHasher}; |
| 12 | 12 | use rustc_hashes::Hash128; |
| 13 | use rustc_hir::def::DefKind; | |
| 13 | 14 | use rustc_hir::def_id::DefId; |
| 14 | 15 | use rustc_middle::bug; |
| 15 | 16 | use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; |
| 16 | use rustc_middle::ty::TyCtxt; | |
| 17 | use rustc_middle::ty::{Instance, TyCtxt}; | |
| 17 | 18 | use rustc_session::cstore::DllImport; |
| 19 | use rustc_target::spec::LlvmAbi; | |
| 18 | 20 | use tracing::debug; |
| 19 | 21 | |
| 20 | use crate::consts::const_alloc_to_llvm; | |
| 22 | use crate::consts::{IsInitOrFini, IsStatic, const_alloc_to_llvm}; | |
| 21 | 23 | pub(crate) use crate::context::CodegenCx; |
| 22 | 24 | use crate::context::{GenericCx, SCx}; |
| 23 | use crate::llvm::{self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value}; | |
| 25 | use crate::llvm::{ | |
| 26 | self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value, const_ptr_auth, | |
| 27 | }; | |
| 28 | ||
| 29 | #[inline] | |
| 30 | pub(crate) fn pauth_fn_attrs() -> &'static [&'static str] { | |
| 31 | // FIXME(jchlanda) This is not an exhaustive list of all `ptrauth`-related attributes, but only | |
| 32 | // those currently supported. The list is expected to grow as additional functionality is | |
| 33 | // implemented, particularly for C++ interoperability. | |
| 34 | &[ | |
| 35 | "aarch64-jump-table-hardening", | |
| 36 | "ptrauth-indirect-gotos", | |
| 37 | "ptrauth-calls", | |
| 38 | "ptrauth-returns", | |
| 39 | "ptrauth-auth-traps", | |
| 40 | ] | |
| 41 | } | |
| 42 | ||
| 43 | pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( | |
| 44 | cx: &CodegenCx<'ll, '_>, | |
| 45 | instance: Instance<'tcx>, | |
| 46 | llfn: &'ll llvm::Value, | |
| 47 | pac: PacMetadata, | |
| 48 | ) -> &'ll llvm::Value { | |
| 49 | if cx.sess().target.llvm_abiname != LlvmAbi::Pauthtest { | |
| 50 | return llfn; | |
| 51 | } | |
| 52 | ||
| 53 | // Only free functions or methods | |
| 54 | let def_id = instance.def_id(); | |
| 55 | if !matches!(cx.tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { | |
| 56 | return llfn; | |
| 57 | } | |
| 58 | // Only C ABI | |
| 59 | let abi = cx.tcx.fn_sig(def_id).skip_binder().abi(); | |
| 60 | if !matches!(abi, ExternAbi::C { .. } | ExternAbi::System { .. }) { | |
| 61 | return llfn; | |
| 62 | } | |
| 63 | // Ignore LLVM intrinsics | |
| 64 | if llvm::get_value_name(llfn).starts_with(b"llvm.") { | |
| 65 | return llfn; | |
| 66 | } | |
| 67 | if Some(def_id) == cx.tcx.lang_items().eh_personality() { | |
| 68 | return llfn; | |
| 69 | } | |
| 70 | ||
| 71 | let addr_diversity = match pac.addr_diversity { | |
| 72 | AddressDiversity::None => None, | |
| 73 | AddressDiversity::Real => Some(llfn), | |
| 74 | AddressDiversity::Synthetic(val) => { | |
| 75 | let llval = cx.const_u64(val); | |
| 76 | let llty = cx.val_ty(llfn); | |
| 77 | Some(unsafe { llvm::LLVMConstIntToPtr(llval, llty) }) | |
| 78 | } | |
| 79 | }; | |
| 80 | const_ptr_auth(llfn, pac.key, pac.disc, addr_diversity) | |
| 81 | } | |
| 24 | 82 | |
| 25 | 83 | /* |
| 26 | 84 | * A note on nomenclature of linking: "extern", "foreign", and "upcall". |
| ... | ... | @@ -268,7 +326,13 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { |
| 268 | 326 | }) |
| 269 | 327 | } |
| 270 | 328 | |
| 271 | fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value { | |
| 329 | fn scalar_to_backend_with_pac( | |
| 330 | &self, | |
| 331 | cv: Scalar, | |
| 332 | layout: abi::Scalar, | |
| 333 | llty: &'ll Type, | |
| 334 | pac: Option<PacMetadata>, | |
| 335 | ) -> &'ll Value { | |
| 272 | 336 | let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; |
| 273 | 337 | match cv { |
| 274 | 338 | Scalar::Int(int) => { |
| ... | ... | @@ -297,8 +361,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { |
| 297 | 361 | self.const_bitcast(llval, llty) |
| 298 | 362 | }; |
| 299 | 363 | } else { |
| 300 | let init = | |
| 301 | const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); | |
| 364 | let init = const_alloc_to_llvm( | |
| 365 | self, | |
| 366 | alloc.inner(), | |
| 367 | IsStatic::No, | |
| 368 | IsInitOrFini::No, | |
| 369 | ); | |
| 302 | 370 | let alloc = alloc.inner(); |
| 303 | 371 | let value = match alloc.mutability { |
| 304 | 372 | Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), |
| ... | ... | @@ -319,7 +387,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { |
| 319 | 387 | value |
| 320 | 388 | } |
| 321 | 389 | } |
| 322 | GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), | |
| 390 | GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, pac), | |
| 323 | 391 | GlobalAlloc::VTable(ty, dyn_ty) => { |
| 324 | 392 | let alloc = self |
| 325 | 393 | .tcx |
| ... | ... | @@ -330,7 +398,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { |
| 330 | 398 | }), |
| 331 | 399 | ))) |
| 332 | 400 | .unwrap_memory(); |
| 333 | let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); | |
| 401 | let init = const_alloc_to_llvm( | |
| 402 | self, | |
| 403 | alloc.inner(), | |
| 404 | IsStatic::No, | |
| 405 | IsInitOrFini::No, | |
| 406 | ); | |
| 334 | 407 | self.static_addr_of_impl(init, alloc.inner().align, None) |
| 335 | 408 | } |
| 336 | 409 | GlobalAlloc::Static(def_id) => { |
compiler/rustc_codegen_llvm/src/consts.rs+76-11| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use std::ops::Range; |
| 2 | 2 | |
| 3 | use rustc_abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange}; | |
| 3 | use rustc_abi::{Align, ExternAbi, HasDataLayout, Primitive, Scalar, Size, WrappingRange}; | |
| 4 | 4 | use rustc_codegen_ssa::common; |
| 5 | 5 | use rustc_codegen_ssa::traits::*; |
| 6 | 6 | use rustc_hir::LangItem; |
| ... | ... | @@ -17,19 +17,30 @@ use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; |
| 17 | 17 | use rustc_middle::ty::{self, Instance}; |
| 18 | 18 | use rustc_middle::{bug, span_bug}; |
| 19 | 19 | use rustc_span::Symbol; |
| 20 | use rustc_target::spec::Arch; | |
| 20 | use rustc_target::spec::{Arch, LlvmAbi}; | |
| 21 | 21 | use tracing::{debug, instrument, trace}; |
| 22 | 22 | |
| 23 | 23 | use crate::common::CodegenCx; |
| 24 | 24 | use crate::errors::SymbolAlreadyDefined; |
| 25 | use crate::llvm::{self, Type, Value}; | |
| 25 | use crate::llvm::{self, Type, Value, const_ptr_auth}; | |
| 26 | 26 | use crate::type_of::LayoutLlvmExt; |
| 27 | 27 | use crate::{base, debuginfo}; |
| 28 | 28 | |
| 29 | /// Indicates whether a value originates from a `static`. | |
| 30 | pub(crate) enum IsStatic { | |
| 31 | Yes, | |
| 32 | No, | |
| 33 | } | |
| 34 | /// Indicates whether a symbol is part of `.init_array` or `.fini_array`. | |
| 35 | pub(crate) enum IsInitOrFini { | |
| 36 | Yes, | |
| 37 | No, | |
| 38 | } | |
| 29 | 39 | pub(crate) fn const_alloc_to_llvm<'ll>( |
| 30 | 40 | cx: &CodegenCx<'ll, '_>, |
| 31 | 41 | alloc: &Allocation, |
| 32 | is_static: bool, | |
| 42 | is_static: IsStatic, | |
| 43 | is_init_fini: IsInitOrFini, | |
| 33 | 44 | ) -> &'ll Value { |
| 34 | 45 | // We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or |
| 35 | 46 | // integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be |
| ... | ... | @@ -38,7 +49,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>( |
| 38 | 49 | // |
| 39 | 50 | // Statics have a guaranteed meaningful address so it's less clear that we want to do |
| 40 | 51 | // something like this; it's also harder. |
| 41 | if !is_static { | |
| 52 | if matches!(is_static, IsStatic::No) { | |
| 42 | 53 | assert!(alloc.len() != 0); |
| 43 | 54 | } |
| 44 | 55 | let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); |
| ... | ... | @@ -109,14 +120,31 @@ pub(crate) fn const_alloc_to_llvm<'ll>( |
| 109 | 120 | as u64; |
| 110 | 121 | |
| 111 | 122 | let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx); |
| 112 | ||
| 113 | llvals.push(cx.scalar_to_backend( | |
| 123 | // Under pointer authentication, function pointers stored in init/fini arrays need special | |
| 124 | // handling. | |
| 125 | let pac_metadata = Some( | |
| 126 | if cx.sess().target.llvm_abiname == LlvmAbi::Pauthtest | |
| 127 | && matches!(is_init_fini, IsInitOrFini::Yes) | |
| 128 | { | |
| 129 | PacMetadata { | |
| 130 | // Must correspond to ptrauth_key_init_fini_pointer from `ptrauth.h`. | |
| 131 | key: 0, | |
| 132 | // ptrauth_string_discriminator("init_fini") | |
| 133 | disc: 0xd9d4, | |
| 134 | addr_diversity: AddressDiversity::Synthetic(1), | |
| 135 | } | |
| 136 | } else { | |
| 137 | PacMetadata::default() | |
| 138 | }, | |
| 139 | ); | |
| 140 | llvals.push(cx.scalar_to_backend_with_pac( | |
| 114 | 141 | InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx), |
| 115 | 142 | Scalar::Initialized { |
| 116 | 143 | value: Primitive::Pointer(address_space), |
| 117 | 144 | valid_range: WrappingRange::full(pointer_size), |
| 118 | 145 | }, |
| 119 | 146 | cx.type_ptr_ext(address_space), |
| 147 | pac_metadata, | |
| 120 | 148 | )); |
| 121 | 149 | next_offset = offset + pointer_size_bytes; |
| 122 | 150 | } |
| ... | ... | @@ -141,7 +169,21 @@ fn codegen_static_initializer<'ll, 'tcx>( |
| 141 | 169 | def_id: DefId, |
| 142 | 170 | ) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> { |
| 143 | 171 | let alloc = cx.tcx.eval_static_initializer(def_id)?; |
| 144 | Ok((const_alloc_to_llvm(cx, alloc.inner(), /*static*/ true), alloc)) | |
| 172 | let attrs = cx.tcx.codegen_fn_attrs(def_id); | |
| 173 | // FIXME(jchlanda) Decide if this could be better served by `ctor` crate. See the discussion | |
| 174 | // here: <https://github.com/rust-lang/rust/pull/155722#discussion_r3320477047> | |
| 175 | let is_in_init_fini: IsInitOrFini = attrs | |
| 176 | .link_section | |
| 177 | .map(|link_section| { | |
| 178 | let s = link_section.as_str(); | |
| 179 | if s.starts_with(".init_array") || s.starts_with(".fini_array") { | |
| 180 | IsInitOrFini::Yes | |
| 181 | } else { | |
| 182 | IsInitOrFini::No | |
| 183 | } | |
| 184 | }) | |
| 185 | .unwrap_or(IsInitOrFini::No); | |
| 186 | Ok((const_alloc_to_llvm(cx, alloc.inner(), IsStatic::Yes, is_in_init_fini), alloc)) | |
| 145 | 187 | } |
| 146 | 188 | |
| 147 | 189 | fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { |
| ... | ... | @@ -164,6 +206,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( |
| 164 | 206 | if let Some(linkage) = attrs.import_linkage { |
| 165 | 207 | debug!("get_static: sym={} linkage={:?}", sym, linkage); |
| 166 | 208 | |
| 209 | let mut should_sign = false; | |
| 167 | 210 | // Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare |
| 168 | 211 | // an extern_weak function, otherwise a global with the desired linkage. |
| 169 | 212 | let g1 = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) { |
| ... | ... | @@ -176,8 +219,13 @@ fn check_and_apply_linkage<'ll, 'tcx>( |
| 176 | 219 | && let ty::FnPtr(sig, header) = args.type_at(0).kind() |
| 177 | 220 | { |
| 178 | 221 | let fn_sig = sig.with(*header); |
| 179 | ||
| 180 | 222 | let fn_abi = cx.fn_abi_of_fn_ptr(fn_sig, ty::List::empty()); |
| 223 | // Decide if the initializer needs to be signed | |
| 224 | if cx.sess().target.llvm_abiname == LlvmAbi::Pauthtest | |
| 225 | && matches!(fn_sig.abi(), ExternAbi::C { .. } | ExternAbi::System { .. }) | |
| 226 | { | |
| 227 | should_sign = true; | |
| 228 | } | |
| 181 | 229 | cx.declare_fn(sym, &fn_abi, None) |
| 182 | 230 | } else { |
| 183 | 231 | cx.declare_global(sym, cx.type_i8()) |
| ... | ... | @@ -207,7 +255,24 @@ fn check_and_apply_linkage<'ll, 'tcx>( |
| 207 | 255 | }); |
| 208 | 256 | llvm::set_linkage(g2, llvm::Linkage::InternalLinkage); |
| 209 | 257 | llvm::set_unnamed_address(g2, llvm::UnnamedAddr::Global); |
| 210 | llvm::set_initializer(g2, g1); | |
| 258 | ||
| 259 | // Sign the function pointer that is used to initialize the global | |
| 260 | let initializer = if should_sign { | |
| 261 | let key: u32 = 0; | |
| 262 | let discriminator: u64 = 0; | |
| 263 | ||
| 264 | const_ptr_auth( | |
| 265 | cx.const_bitcast(g1, llty), | |
| 266 | key, | |
| 267 | discriminator, | |
| 268 | None, /* address_diversity */ | |
| 269 | ) | |
| 270 | } else { | |
| 271 | g1 | |
| 272 | }; | |
| 273 | ||
| 274 | llvm::set_initializer(g2, initializer); | |
| 275 | ||
| 211 | 276 | g2 |
| 212 | 277 | } else if cx.tcx.sess.target.arch == Arch::X86 |
| 213 | 278 | && common::is_mingw_gnu_toolchain(&cx.tcx.sess.target) |
| ... | ... | @@ -776,7 +841,7 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { |
| 776 | 841 | fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value { |
| 777 | 842 | // FIXME: should we cache `const_alloc_to_llvm` to avoid repeating this for the |
| 778 | 843 | // same `ConstAllocation`? |
| 779 | let cv = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); | |
| 844 | let cv = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No); | |
| 780 | 845 | |
| 781 | 846 | let gv = self.static_addr_of_impl(cv, alloc.inner().align, kind); |
| 782 | 847 | // static_addr_of_impl returns the bare global variable, which might not be in the default |
compiler/rustc_codegen_llvm/src/context.rs+46-9| ... | ... | @@ -727,6 +727,24 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { |
| 727 | 727 | } |
| 728 | 728 | } |
| 729 | 729 | |
| 730 | pub(crate) fn add_ptrauth_elf_got_flag(&self) { | |
| 731 | llvm::add_module_flag_u32( | |
| 732 | self.llmod, | |
| 733 | llvm::ModuleFlagMergeBehavior::Error, | |
| 734 | "ptrauth-elf-got", | |
| 735 | 1, | |
| 736 | ); | |
| 737 | } | |
| 738 | ||
| 739 | pub(crate) fn add_ptrauth_sign_personality_flag(&self) { | |
| 740 | llvm::add_module_flag_u32( | |
| 741 | self.llmod, | |
| 742 | llvm::ModuleFlagMergeBehavior::Error, | |
| 743 | "ptrauth-sign-personality", | |
| 744 | 1, | |
| 745 | ); | |
| 746 | } | |
| 747 | ||
| 730 | 748 | // We do our best here to match what Clang does when compiling Objective-C natively. |
| 731 | 749 | // See Clang's `CGObjCCommonMac::EmitImageInfo`: |
| 732 | 750 | // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5085 |
| ... | ... | @@ -871,8 +889,24 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { |
| 871 | 889 | get_fn(self, instance) |
| 872 | 890 | } |
| 873 | 891 | |
| 874 | fn get_fn_addr(&self, instance: Instance<'tcx>) -> &'ll Value { | |
| 875 | get_fn(self, instance) | |
| 892 | fn get_fn_addr(&self, instance: Instance<'tcx>, pac: Option<PacMetadata>) -> &'ll Value { | |
| 893 | // When pointer authentication metadata is provided, `get_fn_addr` will | |
| 894 | // attempt to sign the pointer using LLVM's `ConstPtrAuth` constant | |
| 895 | // expression. | |
| 896 | // | |
| 897 | // FIXME(jchlanda) Currently, all function addresses requested from | |
| 898 | // within LLVM codegen are signed. This behavior is too broad, resulting | |
| 899 | // in the logic being applied to function values, not just pointers | |
| 900 | // (addresses). | |
| 901 | // | |
| 902 | // See the discussion in the rust-lang issue: | |
| 903 | // <https://github.com/rust-lang/rust/issues/152532>, and comment in | |
| 904 | // builder's `ptrauth_operand_bundle`. | |
| 905 | let llfn = get_fn(self, instance); | |
| 906 | match pac { | |
| 907 | Some(pac) => common::maybe_sign_fn_ptr(self, instance, llfn, pac), | |
| 908 | None => llfn, | |
| 909 | } | |
| 876 | 910 | } |
| 877 | 911 | |
| 878 | 912 | fn eh_personality(&self) -> &'ll Value { |
| ... | ... | @@ -914,13 +948,16 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { |
| 914 | 948 | |
| 915 | 949 | let tcx = self.tcx; |
| 916 | 950 | let llfn = match tcx.lang_items().eh_personality() { |
| 917 | Some(def_id) if name.is_none() => self.get_fn_addr(ty::Instance::expect_resolve( | |
| 918 | tcx, | |
| 919 | self.typing_env(), | |
| 920 | def_id, | |
| 921 | ty::List::empty(), | |
| 922 | DUMMY_SP, | |
| 923 | )), | |
| 951 | Some(def_id) if name.is_none() => self.get_fn_addr( | |
| 952 | ty::Instance::expect_resolve( | |
| 953 | tcx, | |
| 954 | self.typing_env(), | |
| 955 | def_id, | |
| 956 | ty::List::empty(), | |
| 957 | DUMMY_SP, | |
| 958 | ), | |
| 959 | Some(PacMetadata::default()), | |
| 960 | ), | |
| 924 | 961 | _ => { |
| 925 | 962 | let name = name.unwrap_or("rust_eh_personality"); |
| 926 | 963 | if let Some(llfn) = self.get_declared_value(name) { |
compiler/rustc_codegen_llvm/src/intrinsic.rs+10-2| ... | ... | @@ -28,7 +28,7 @@ use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC; |
| 28 | 28 | use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; |
| 29 | 29 | use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; |
| 30 | 30 | use rustc_target::callconv::PassMode; |
| 31 | use rustc_target::spec::Arch; | |
| 31 | use rustc_target::spec::{Arch, LlvmAbi}; | |
| 32 | 32 | use tracing::debug; |
| 33 | 33 | |
| 34 | 34 | use crate::abi::FnAbiLlvmExt; |
| ... | ... | @@ -37,6 +37,7 @@ use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; |
| 37 | 37 | use crate::builder::gpu_offload::{ |
| 38 | 38 | OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload, |
| 39 | 39 | }; |
| 40 | use crate::common::pauth_fn_attrs; | |
| 40 | 41 | use crate::context::CodegenCx; |
| 41 | 42 | use crate::declare::declare_raw_fn; |
| 42 | 43 | use crate::errors::{ |
| ... | ... | @@ -44,7 +45,7 @@ use crate::errors::{ |
| 44 | 45 | OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, |
| 45 | 46 | }; |
| 46 | 47 | use crate::intrinsic::ty::typetree::fnc_typetrees; |
| 47 | use crate::llvm::{self, Type, Value}; | |
| 48 | use crate::llvm::{self, Attribute, AttributePlace, Type, Value}; | |
| 48 | 49 | use crate::type_of::LayoutLlvmExt; |
| 49 | 50 | use crate::va_arg::emit_va_arg; |
| 50 | 51 | |
| ... | ... | @@ -1711,6 +1712,13 @@ fn get_rust_try_fn<'a, 'll, 'tcx>( |
| 1711 | 1712 | hir::Safety::Unsafe, |
| 1712 | 1713 | )); |
| 1713 | 1714 | let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen); |
| 1715 | if cx.sess().target.llvm_abiname == LlvmAbi::Pauthtest { | |
| 1716 | let attrs: Vec<&Attribute> = | |
| 1717 | pauth_fn_attrs().iter().map(|name| llvm::CreateAttrString(cx.llcx, name)).collect(); | |
| 1718 | let (_ty, rust_try_fn) = rust_try; | |
| 1719 | crate::attributes::apply_to_llfn(rust_try_fn, AttributePlace::Function, &attrs); | |
| 1720 | } | |
| 1721 | ||
| 1714 | 1722 | cx.rust_try_fn.set(Some(rust_try)); |
| 1715 | 1723 | rust_try |
| 1716 | 1724 | } |
compiler/rustc_codegen_llvm/src/llvm/ffi.rs+8| ... | ... | @@ -2647,4 +2647,12 @@ unsafe extern "C" { |
| 2647 | 2647 | Aliasee: &Value, |
| 2648 | 2648 | Name: *const c_char, |
| 2649 | 2649 | ) -> &'ll Value; |
| 2650 | ||
| 2651 | pub(crate) fn LLVMRustConstPtrAuth( | |
| 2652 | ptr: *const Value, | |
| 2653 | key: u32, | |
| 2654 | disc: u64, | |
| 2655 | addr_diversity: *const Value, | |
| 2656 | deactivation_symbol: *const Value, | |
| 2657 | ) -> *const Value; | |
| 2650 | 2658 | } |
compiler/rustc_codegen_llvm/src/llvm/mod.rs+16| ... | ... | @@ -475,3 +475,19 @@ pub(crate) fn add_alias<'ll>( |
| 475 | 475 | ) -> &'ll Value { |
| 476 | 476 | unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) } |
| 477 | 477 | } |
| 478 | ||
| 479 | /// Safe wrapper for `LLVMRustConstPtrAuth`. | |
| 480 | pub(crate) fn const_ptr_auth<'ll>( | |
| 481 | ptr: &'ll Value, | |
| 482 | key: u32, | |
| 483 | disc: u64, | |
| 484 | addr_diversity: Option<&'ll Value>, | |
| 485 | ) -> &'ll Value { | |
| 486 | unsafe { | |
| 487 | let addr_div_ptr = addr_diversity.map_or(std::ptr::null(), |v| v as *const Value); | |
| 488 | let deactivation_symbol = std::ptr::null(); | |
| 489 | let result = | |
| 490 | LLVMRustConstPtrAuth(ptr as *const Value, key, disc, addr_div_ptr, deactivation_symbol); | |
| 491 | &*result | |
| 492 | } | |
| 493 | } |
compiler/rustc_codegen_ssa/src/base.rs+2-2| ... | ... | @@ -493,7 +493,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( |
| 493 | 493 | return None; |
| 494 | 494 | } |
| 495 | 495 | |
| 496 | let main_llfn = cx.get_fn_addr(instance); | |
| 496 | let main_llfn = cx.get_fn_addr(instance, Some(PacMetadata::default())); | |
| 497 | 497 | |
| 498 | 498 | let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type); |
| 499 | 499 | return Some(entry_fn); |
| ... | ... | @@ -554,7 +554,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( |
| 554 | 554 | cx.tcx().mk_args(&[main_ret_ty.into()]), |
| 555 | 555 | DUMMY_SP, |
| 556 | 556 | ); |
| 557 | let start_fn = cx.get_fn_addr(start_instance); | |
| 557 | let start_fn = cx.get_fn_addr(start_instance, Some(PacMetadata::default())); | |
| 558 | 558 | |
| 559 | 559 | let i8_ty = cx.type_i8(); |
| 560 | 560 | let arg_sigpipe = bx.const_u8(sigpipe); |
compiler/rustc_codegen_ssa/src/common.rs+5-1| ... | ... | @@ -117,7 +117,11 @@ pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( |
| 117 | 117 | let tcx = bx.tcx(); |
| 118 | 118 | let def_id = tcx.require_lang_item(li, span); |
| 119 | 119 | let instance = ty::Instance::mono(tcx, def_id); |
| 120 | (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance) | |
| 120 | ( | |
| 121 | bx.fn_abi_of_instance(instance, ty::List::empty()), | |
| 122 | bx.get_fn_addr(instance, Some(PacMetadata::default())), | |
| 123 | instance, | |
| 124 | ) | |
| 121 | 125 | } |
| 122 | 126 | |
| 123 | 127 | pub(crate) fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( |
compiler/rustc_codegen_ssa/src/mir/block.rs+3-3| ... | ... | @@ -686,7 +686,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 686 | 686 | } |
| 687 | 687 | _ => ( |
| 688 | 688 | false, |
| 689 | bx.get_fn_addr(drop_fn), | |
| 689 | bx.get_fn_addr(drop_fn, Some(PacMetadata::default())), | |
| 690 | 690 | bx.fn_abi_of_instance(drop_fn, ty::List::empty()), |
| 691 | 691 | drop_fn, |
| 692 | 692 | ), |
| ... | ... | @@ -1097,7 +1097,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1097 | 1097 | ) |
| 1098 | 1098 | .unwrap(); |
| 1099 | 1099 | |
| 1100 | (None, Some(bx.get_fn_addr(instance))) | |
| 1100 | (None, Some(bx.get_fn_addr(instance, Some(PacMetadata::default())))) | |
| 1101 | 1101 | } |
| 1102 | 1102 | _ => (Some(instance), None), |
| 1103 | 1103 | } |
| ... | ... | @@ -1410,7 +1410,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 1410 | 1410 | } |
| 1411 | 1411 | |
| 1412 | 1412 | let fn_ptr = match (instance, llfn) { |
| 1413 | (Some(instance), None) => bx.get_fn_addr(instance), | |
| 1413 | (Some(instance), None) => bx.get_fn_addr(instance, Some(PacMetadata::default())), | |
| 1414 | 1414 | (_, Some(llfn)) => llfn, |
| 1415 | 1415 | _ => span_bug!(fn_span, "no instance or llfn for call"), |
| 1416 | 1416 | }; |
compiler/rustc_codegen_ssa/src/mir/rvalue.rs+13-3| ... | ... | @@ -434,7 +434,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 434 | 434 | args, |
| 435 | 435 | ) |
| 436 | 436 | .unwrap(); |
| 437 | OperandValue::Immediate(bx.get_fn_addr(instance)) | |
| 437 | OperandValue::Immediate( | |
| 438 | bx.get_fn_addr( | |
| 439 | instance, | |
| 440 | Some(PacMetadata::default()), | |
| 441 | ), | |
| 442 | ) | |
| 438 | 443 | } |
| 439 | 444 | _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), |
| 440 | 445 | } |
| ... | ... | @@ -448,7 +453,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 448 | 453 | args, |
| 449 | 454 | ty::ClosureKind::FnOnce, |
| 450 | 455 | ); |
| 451 | OperandValue::Immediate(bx.cx().get_fn_addr(instance)) | |
| 456 | OperandValue::Immediate( | |
| 457 | bx.cx().get_fn_addr( | |
| 458 | instance, | |
| 459 | Some(PacMetadata::default()), | |
| 460 | ), | |
| 461 | ) | |
| 452 | 462 | } |
| 453 | 463 | _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), |
| 454 | 464 | } |
| ... | ... | @@ -668,7 +678,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { |
| 668 | 678 | def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(def_id)), |
| 669 | 679 | args: ty::GenericArgs::empty(), |
| 670 | 680 | }; |
| 671 | let fn_ptr = bx.get_fn_addr(instance); | |
| 681 | let fn_ptr = bx.get_fn_addr(instance, Some(PacMetadata::default())); | |
| 672 | 682 | let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); |
| 673 | 683 | let fn_ty = bx.fn_decl_backend_type(fn_abi); |
| 674 | 684 | let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() { |
compiler/rustc_codegen_ssa/src/traits/consts.rs+11-1| ... | ... | @@ -2,6 +2,7 @@ use rustc_abi as abi; |
| 2 | 2 | use rustc_middle::mir::interpret::Scalar; |
| 3 | 3 | |
| 4 | 4 | use super::BackendTypes; |
| 5 | use crate::traits::PacMetadata; | |
| 5 | 6 | |
| 6 | 7 | pub trait ConstCodegenMethods: BackendTypes { |
| 7 | 8 | // Constant constructors |
| ... | ... | @@ -38,7 +39,16 @@ pub trait ConstCodegenMethods: BackendTypes { |
| 38 | 39 | fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>; |
| 39 | 40 | fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>; |
| 40 | 41 | |
| 41 | fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; | |
| 42 | fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value { | |
| 43 | self.scalar_to_backend_with_pac(cv, layout, llty, None) | |
| 44 | } | |
| 45 | fn scalar_to_backend_with_pac( | |
| 46 | &self, | |
| 47 | cv: Scalar, | |
| 48 | layout: abi::Scalar, | |
| 49 | llty: Self::Type, | |
| 50 | pac: Option<PacMetadata>, | |
| 51 | ) -> Self::Value; | |
| 42 | 52 | |
| 43 | 53 | fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; |
| 44 | 54 | } |
compiler/rustc_codegen_ssa/src/traits/misc.rs+30-1| ... | ... | @@ -7,6 +7,35 @@ use rustc_span::Symbol; |
| 7 | 7 | |
| 8 | 8 | use super::BackendTypes; |
| 9 | 9 | |
| 10 | /// Strategy for incorporating address-based diversity into PAC computation. | |
| 11 | #[derive(Default)] | |
| 12 | pub enum AddressDiversity { | |
| 13 | /// No address diversity is applied. | |
| 14 | #[default] | |
| 15 | None, | |
| 16 | /// Use the actual memory address for diversification. | |
| 17 | Real, | |
| 18 | /// Use a fixed synthetic value instead of the real address, | |
| 19 | /// i.e. `1` is used for `.init_array` / `.fini_array`. | |
| 20 | Synthetic(u64), | |
| 21 | } | |
| 22 | ||
| 23 | /// Metadata used for pointer authentication. | |
| 24 | pub struct PacMetadata { | |
| 25 | /// The PAC key to use. | |
| 26 | pub key: u32, | |
| 27 | /// Discriminator value used to diversify the PAC. | |
| 28 | pub disc: u64, | |
| 29 | /// Controls how address diversity is applied when computing the PAC. | |
| 30 | pub addr_diversity: AddressDiversity, | |
| 31 | } | |
| 32 | ||
| 33 | impl Default for PacMetadata { | |
| 34 | fn default() -> Self { | |
| 35 | PacMetadata { key: 0, disc: 0, addr_diversity: AddressDiversity::default() } | |
| 36 | } | |
| 37 | } | |
| 38 | ||
| 10 | 39 | pub trait MiscCodegenMethods<'tcx>: BackendTypes { |
| 11 | 40 | fn vtables( |
| 12 | 41 | &self, |
| ... | ... | @@ -19,7 +48,7 @@ pub trait MiscCodegenMethods<'tcx>: BackendTypes { |
| 19 | 48 | ) { |
| 20 | 49 | } |
| 21 | 50 | fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; |
| 22 | fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; | |
| 51 | fn get_fn_addr(&self, instance: Instance<'tcx>, pac: Option<PacMetadata>) -> Self::Value; | |
| 23 | 52 | fn eh_personality(&self) -> Self::Function; |
| 24 | 53 | fn sess(&self) -> &Session; |
| 25 | 54 | fn set_frame_pointer_type(&self, llfn: Self::Function); |
compiler/rustc_codegen_ssa/src/traits/mod.rs+1-1| ... | ... | @@ -42,7 +42,7 @@ pub use self::coverageinfo::CoverageInfoBuilderMethods; |
| 42 | 42 | pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; |
| 43 | 43 | pub use self::declare::PreDefineCodegenMethods; |
| 44 | 44 | pub use self::intrinsic::IntrinsicCallBuilderMethods; |
| 45 | pub use self::misc::MiscCodegenMethods; | |
| 45 | pub use self::misc::{AddressDiversity, MiscCodegenMethods, PacMetadata}; | |
| 46 | 46 | pub use self::statics::{StaticBuilderMethods, StaticCodegenMethods}; |
| 47 | 47 | pub use self::type_::{ |
| 48 | 48 | ArgAbiBuilderMethods, BaseTypeCodegenMethods, DerivedTypeCodegenMethods, |
compiler/rustc_hir/src/def.rs-37| ... | ... | @@ -448,43 +448,6 @@ impl DefKind { |
| 448 | 448 | | DefKind::ExternCrate => false, |
| 449 | 449 | } |
| 450 | 450 | } |
| 451 | ||
| 452 | /// Returns `true` if `self` is a kind of definition that does not have its own | |
| 453 | /// type-checking context, i.e. closure, coroutine or inline const. | |
| 454 | #[inline] | |
| 455 | pub fn is_typeck_child(self) -> bool { | |
| 456 | match self { | |
| 457 | DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody => true, | |
| 458 | DefKind::Mod | |
| 459 | | DefKind::Struct | |
| 460 | | DefKind::Union | |
| 461 | | DefKind::Enum | |
| 462 | | DefKind::Variant | |
| 463 | | DefKind::Trait | |
| 464 | | DefKind::TyAlias | |
| 465 | | DefKind::ForeignTy | |
| 466 | | DefKind::TraitAlias | |
| 467 | | DefKind::AssocTy | |
| 468 | | DefKind::TyParam | |
| 469 | | DefKind::Fn | |
| 470 | | DefKind::Const { .. } | |
| 471 | | DefKind::ConstParam | |
| 472 | | DefKind::Static { .. } | |
| 473 | | DefKind::Ctor(_, _) | |
| 474 | | DefKind::AssocFn | |
| 475 | | DefKind::AssocConst { .. } | |
| 476 | | DefKind::Macro(_) | |
| 477 | | DefKind::ExternCrate | |
| 478 | | DefKind::Use | |
| 479 | | DefKind::ForeignMod | |
| 480 | | DefKind::AnonConst | |
| 481 | | DefKind::OpaqueTy | |
| 482 | | DefKind::Field | |
| 483 | | DefKind::LifetimeParam | |
| 484 | | DefKind::GlobalAsm | |
| 485 | | DefKind::Impl { .. } => false, | |
| 486 | } | |
| 487 | } | |
| 488 | 451 | } |
| 489 | 452 | |
| 490 | 453 | /// The resolution of a path or export. |
compiler/rustc_hir/src/hir.rs+13-1| ... | ... | @@ -387,12 +387,24 @@ pub struct PathSegment<'hir> { |
| 387 | 387 | /// out of those only the segments with no type parameters |
| 388 | 388 | /// to begin with, e.g., `Vec::new` is `<Vec<..>>::new::<..>`. |
| 389 | 389 | pub infer_args: bool, |
| 390 | ||
| 391 | /// Whether this segment is a delegation's child segment: | |
| 392 | /// `reuse Trait::foo`, in this case `foo` is a delegation's child segment. | |
| 393 | /// Used for faster check during generic args lowering. | |
| 394 | pub delegation_child_segment: bool, | |
| 390 | 395 | } |
| 391 | 396 | |
| 392 | 397 | impl<'hir> PathSegment<'hir> { |
| 393 | 398 | /// Converts an identifier to the corresponding segment. |
| 394 | 399 | pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> { |
| 395 | PathSegment { ident, hir_id, res, infer_args: true, args: None } | |
| 400 | PathSegment { | |
| 401 | ident, | |
| 402 | hir_id, | |
| 403 | res, | |
| 404 | infer_args: true, | |
| 405 | args: None, | |
| 406 | delegation_child_segment: false, | |
| 407 | } | |
| 396 | 408 | } |
| 397 | 409 | |
| 398 | 410 | pub fn invalid() -> Self { |
compiler/rustc_hir/src/intravisit.rs+2-1| ... | ... | @@ -1468,7 +1468,8 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>( |
| 1468 | 1468 | visitor: &mut V, |
| 1469 | 1469 | segment: &'v PathSegment<'v>, |
| 1470 | 1470 | ) -> V::Result { |
| 1471 | let PathSegment { ident, hir_id, res: _, args, infer_args: _ } = segment; | |
| 1471 | let PathSegment { ident, hir_id, res: _, args, infer_args: _, delegation_child_segment: _ } = | |
| 1472 | segment; | |
| 1472 | 1473 | try_visit!(visitor.visit_ident(*ident)); |
| 1473 | 1474 | try_visit!(visitor.visit_id(*hir_id)); |
| 1474 | 1475 | visit_opt!(visitor, visit_generic_args, *args); |
compiler/rustc_hir_analysis/src/collect.rs+4-2| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | //! crate as a kind of pass. This should eventually be factored away. |
| 16 | 16 | |
| 17 | 17 | use std::cell::Cell; |
| 18 | use std::{assert_matches, iter}; | |
| 18 | use std::{assert_matches, debug_assert_matches, iter}; | |
| 19 | 19 | |
| 20 | 20 | use rustc_abi::{ExternAbi, Size}; |
| 21 | 21 | use rustc_ast::Recovered; |
| ... | ... | @@ -1635,10 +1635,12 @@ fn const_param_default<'tcx>( |
| 1635 | 1635 | } |
| 1636 | 1636 | |
| 1637 | 1637 | fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind { |
| 1638 | debug_assert_matches!(tcx.def_kind(def), DefKind::AnonConst | DefKind::InlineConst); | |
| 1638 | 1639 | let hir_id = tcx.local_def_id_to_hir_id(def); |
| 1639 | 1640 | let const_arg_id = tcx.parent_hir_id(hir_id); |
| 1640 | 1641 | match tcx.hir_node(const_arg_id) { |
| 1641 | hir::Node::ConstArg(_) => { | |
| 1642 | hir::Node::ConstArg(const_arg) => { | |
| 1643 | debug_assert_matches!(const_arg.kind, hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) if *def_id == def); | |
| 1642 | 1644 | let parent_hir_node = tcx.hir_node(tcx.parent_hir_id(const_arg_id)); |
| 1643 | 1645 | if tcx.features().generic_const_exprs() { |
| 1644 | 1646 | ty::AnonConstKind::GCE |
compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs+1| ... | ... | @@ -467,6 +467,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 467 | 467 | res: Res::Err, |
| 468 | 468 | args: Some(constraint.gen_args), |
| 469 | 469 | infer_args: false, |
| 470 | delegation_child_segment: false, | |
| 470 | 471 | }; |
| 471 | 472 | |
| 472 | 473 | let alias_args = self.lower_generic_args_of_assoc_item( |
compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs+1| ... | ... | @@ -471,6 +471,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 471 | 471 | res: Res::Err, |
| 472 | 472 | args: Some(constraint.gen_args), |
| 473 | 473 | infer_args: false, |
| 474 | delegation_child_segment: false, | |
| 474 | 475 | }; |
| 475 | 476 | |
| 476 | 477 | let alias_args = self.lower_generic_args_of_assoc_item( |
compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs+1-1| ... | ... | @@ -434,7 +434,7 @@ pub(crate) fn check_generic_arg_count( |
| 434 | 434 | |
| 435 | 435 | // Suppress this warning for delegations as it is compiler generated and lifetimes are |
| 436 | 436 | // propagated while late-bound lifetimes may be present. |
| 437 | let explicit_late_bound = match tcx.hir_is_delegation_child_segment(seg) { | |
| 437 | let explicit_late_bound = match seg.delegation_child_segment { | |
| 438 | 438 | true => ExplicitLateBound::No, |
| 439 | 439 | false => prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos), |
| 440 | 440 | }; |
compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs+5-9| ... | ... | @@ -483,7 +483,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 483 | 483 | let tcx = self.tcx(); |
| 484 | 484 | let parent_def_id = self.item_def_id(); |
| 485 | 485 | if let Res::Def(DefKind::ConstParam, _) = res |
| 486 | && tcx.def_kind(parent_def_id) == DefKind::AnonConst | |
| 486 | && matches!(tcx.def_kind(parent_def_id), DefKind::AnonConst | DefKind::InlineConst) | |
| 487 | 487 | && let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id) |
| 488 | 488 | { |
| 489 | 489 | let folder = ForbidParamUsesFolder { |
| ... | ... | @@ -512,15 +512,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 512 | 512 | // Inline consts and closures can be nested inside anon consts that forbid generic |
| 513 | 513 | // params (e.g. an enum discriminant). Walk up the def parent chain to find the |
| 514 | 514 | // nearest enclosing AnonConst and use that to determine the context. |
| 515 | let parent_def_id = tcx.typeck_root_def_id(parent_def_id.into()); | |
| 516 | ||
| 515 | 517 | let anon_const_def_id = match tcx.def_kind(parent_def_id) { |
| 516 | 518 | DefKind::AnonConst => parent_def_id, |
| 517 | DefKind::InlineConst | DefKind::Closure => { | |
| 518 | let root = tcx.typeck_root_def_id(parent_def_id.into()); | |
| 519 | match tcx.def_kind(root) { | |
| 520 | DefKind::AnonConst => root.expect_local(), | |
| 521 | _ => return None, | |
| 522 | } | |
| 523 | } | |
| 519 | DefKind::InlineConst if tcx.is_type_system_inline_const(parent_def_id) => parent_def_id, | |
| 524 | 520 | _ => return None, |
| 525 | 521 | }; |
| 526 | 522 | |
| ... | ... | @@ -870,7 +866,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 870 | 866 | span, |
| 871 | 867 | generic_args: segment.args(), |
| 872 | 868 | infer_args: segment.infer_args, |
| 873 | create_synth_args: tcx.hir_is_delegation_child_segment(segment), | |
| 869 | create_synth_args: segment.delegation_child_segment, | |
| 874 | 870 | incorrect_args: &arg_count.correct, |
| 875 | 871 | }; |
| 876 | 872 |
compiler/rustc_hir_analysis/src/lib.rs+6-2| ... | ... | @@ -186,9 +186,13 @@ pub fn check_crate(tcx: TyCtxt<'_>) { |
| 186 | 186 | } |
| 187 | 187 | _ => (), |
| 188 | 188 | } |
| 189 | // Skip `AnonConst`s because we feed their `type_of`. | |
| 189 | // Skip `AnonConst`s and type system `InlineConst`s because we feed their `type_of` in | |
| 190 | // `feed_anon_const_type`. | |
| 190 | 191 | // Also skip items for which typeck forwards to parent typeck. |
| 191 | if !(matches!(def_kind, DefKind::AnonConst) || def_kind.is_typeck_child()) { | |
| 192 | if !(def_kind == DefKind::AnonConst | |
| 193 | || def_kind == DefKind::InlineConst && tcx.is_type_system_inline_const(item_def_id) | |
| 194 | || tcx.is_typeck_child(item_def_id.to_def_id())) | |
| 195 | { | |
| 192 | 196 | tcx.ensure_ok().typeck(item_def_id); |
| 193 | 197 | } |
| 194 | 198 | // Ensure we generate the new `DefId` before finishing `check_crate`. |
compiler/rustc_hir_typeck/src/callee.rs+11-6| ... | ... | @@ -9,11 +9,11 @@ use rustc_hir::{self as hir, HirId, LangItem, find_attr}; |
| 9 | 9 | use rustc_hir_analysis::autoderef::Autoderef; |
| 10 | 10 | use rustc_infer::infer::BoundRegionConversionTime; |
| 11 | 11 | use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; |
| 12 | use rustc_middle::bug; | |
| 12 | 13 | use rustc_middle::ty::adjustment::{ |
| 13 | 14 | Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, |
| 14 | 15 | }; |
| 15 | 16 | use rustc_middle::ty::{self, FnSig, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, Unnormalized}; |
| 16 | use rustc_middle::{bug, span_bug}; | |
| 17 | 17 | use rustc_span::def_id::LocalDefId; |
| 18 | 18 | use rustc_span::{Ident, Span, sym}; |
| 19 | 19 | use rustc_target::spec::{AbiMap, AbiMapping}; |
| ... | ... | @@ -1186,11 +1186,16 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { |
| 1186 | 1186 | ); |
| 1187 | 1187 | } |
| 1188 | 1188 | None => { |
| 1189 | span_bug!( | |
| 1190 | self.call_expr.span, | |
| 1191 | "Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for `{}`", | |
| 1192 | self.closure_ty | |
| 1193 | ) | |
| 1189 | let guar = fcx.tainted_by_errors().unwrap_or_else(|| { | |
| 1190 | fcx.dcx().span_delayed_bug( | |
| 1191 | self.call_expr.span, | |
| 1192 | format!( | |
| 1193 | "Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for `{}`", | |
| 1194 | self.closure_ty | |
| 1195 | ), | |
| 1196 | ) | |
| 1197 | }); | |
| 1198 | fcx.write_resolution(self.call_expr.hir_id, Err(guar)); | |
| 1194 | 1199 | } |
| 1195 | 1200 | } |
| 1196 | 1201 | } |
compiler/rustc_hir_typeck/src/loops.rs+5| ... | ... | @@ -84,6 +84,11 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir |
| 84 | 84 | CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() }; |
| 85 | 85 | let cx = match tcx.def_kind(def_id) { |
| 86 | 86 | DefKind::AnonConst => AnonConst, |
| 87 | DefKind::InlineConst => { | |
| 88 | // only type system inline consts are typeck roots | |
| 89 | debug_assert!(tcx.is_type_system_inline_const(def_id)); | |
| 90 | ConstBlock | |
| 91 | } | |
| 87 | 92 | _ => Fn, |
| 88 | 93 | }; |
| 89 | 94 | check.with_context(cx, |v| v.visit_body(body)); |
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp+10| ... | ... | @@ -288,7 +288,11 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, |
| 288 | 288 | // Just print a bare list of target CPU names, and let Rust-side code handle |
| 289 | 289 | // the full formatting of `--print=target-cpus`. |
| 290 | 290 | for (auto &CPU : CPUTable) { |
| 291 | #if LLVM_VERSION_GE(23, 0) | |
| 292 | OS << CPU.key() << "\n"; | |
| 293 | #else | |
| 291 | 294 | OS << CPU.Key << "\n"; |
| 295 | #endif | |
| 292 | 296 | } |
| 293 | 297 | } |
| 294 | 298 | |
| ... | ... | @@ -315,9 +319,15 @@ extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index, |
| 315 | 319 | #endif |
| 316 | 320 | const ArrayRef<SubtargetFeatureKV> FeatTable = |
| 317 | 321 | MCInfo.getAllProcessorFeatures(); |
| 322 | #if LLVM_VERSION_GE(23, 0) | |
| 323 | const SubtargetFeatureKV &Feat = FeatTable[Index]; | |
| 324 | *Feature = Feat.key(); | |
| 325 | *Desc = Feat.desc(); | |
| 326 | #else | |
| 318 | 327 | const SubtargetFeatureKV Feat = FeatTable[Index]; |
| 319 | 328 | *Feature = Feat.Key; |
| 320 | 329 | *Desc = Feat.Desc; |
| 330 | #endif | |
| 321 | 331 | } |
| 322 | 332 | |
| 323 | 333 | extern "C" const char *LLVMRustGetHostCPUName(size_t *OutLen) { |
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp+29| ... | ... | @@ -1848,6 +1848,35 @@ extern "C" bool LLVMRustIsTargetIntrinsic(unsigned ID) { |
| 1848 | 1848 | return Intrinsic::isTargetIntrinsic(ID); |
| 1849 | 1849 | } |
| 1850 | 1850 | |
| 1851 | extern "C" LLVMValueRef LLVMRustConstPtrAuth(LLVMValueRef Ptr, uint32_t Key, | |
| 1852 | uint64_t Disc, | |
| 1853 | LLVMValueRef AddrDiversity, | |
| 1854 | LLVMValueRef DeactivationSymbol) { | |
| 1855 | auto *C = cast<Constant>(unwrap<Value>(Ptr)); | |
| 1856 | assert(C->getType()->isPointerTy() && "Expected pointer type"); | |
| 1857 | assert(!isa<UndefValue>(C) && "Unexpected undef in const_ptr_auth"); | |
| 1858 | assert(!isa<ConstantPointerNull>(C) && "Unexpected null in const_ptr_auth"); | |
| 1859 | ||
| 1860 | LLVMContext &Ctx = C->getContext(); | |
| 1861 | auto *KeyC = ConstantInt::get(Type::getInt32Ty(Ctx), Key); | |
| 1862 | auto *DiscC = ConstantInt::get(Type::getInt64Ty(Ctx), Disc); | |
| 1863 | auto *PTy = cast<PointerType>(C->getType()); | |
| 1864 | Constant *AddrDiv = | |
| 1865 | AddrDiversity ? dyn_cast<Constant>(unwrap<Value>(AddrDiversity)) | |
| 1866 | : ConstantPointerNull::get(cast<PointerType>(C->getType())); | |
| 1867 | assert(AddrDiv && "Failed to get Address Diversity"); | |
| 1868 | #if LLVM_VERSION_GE(22, 0) | |
| 1869 | Constant *DeactivationSym = | |
| 1870 | DeactivationSymbol ? dyn_cast<Constant>(unwrap<Value>(DeactivationSymbol)) | |
| 1871 | : ConstantPointerNull::get(PTy); | |
| 1872 | assert(DeactivationSym && "Failed to get Deactivation Symbol"); | |
| 1873 | ||
| 1874 | return wrap(ConstantPtrAuth::get(C, KeyC, DiscC, AddrDiv, DeactivationSym)); | |
| 1875 | #else | |
| 1876 | return wrap(ConstantPtrAuth::get(C, KeyC, DiscC, AddrDiv)); | |
| 1877 | #endif | |
| 1878 | } | |
| 1879 | ||
| 1851 | 1880 | // Statically assert that the fixed metadata kind IDs declared in |
| 1852 | 1881 | // `metadata_kind.rs` match the ones actually used by LLVM. |
| 1853 | 1882 | #define FIXED_MD_KIND(VARIANT, VALUE) \ |
compiler/rustc_metadata/src/diagnostics.rs+15| ... | ... | @@ -704,3 +704,18 @@ pub(crate) struct MitigationLessStrictInDependency { |
| 704 | 704 | pub mitigation_level: String, |
| 705 | 705 | pub extern_crate: Symbol, |
| 706 | 706 | } |
| 707 | ||
| 708 | #[derive(Diagnostic)] | |
| 709 | pub(crate) enum StaticLinkingNotSupported<'a> { | |
| 710 | #[diag( | |
| 711 | "static linking of `{$lib_name}` is not supported on `{$target}`; using dynamic linking instead" | |
| 712 | )] | |
| 713 | #[help("remove `kind = \"static\"` and ensure a shared library is available")] | |
| 714 | UserRequested { lib_name: Symbol, target: &'a str }, | |
| 715 | ||
| 716 | #[diag( | |
| 717 | "library `{$lib_name}` is linked statically by a dependency, but `{$target}` requires dynamic linking; using dynamic linking instead" | |
| 718 | )] | |
| 719 | #[help("ensure a shared library is available")] | |
| 720 | FromDependency { lib_name: Symbol, target: &'a str }, | |
| 721 | } |
compiler/rustc_metadata/src/native_libs.rs+25| ... | ... | @@ -197,6 +197,31 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib> |
| 197 | 197 | } |
| 198 | 198 | } |
| 199 | 199 | collector.process_command_line(); |
| 200 | for lib in &mut collector.libs { | |
| 201 | // FIXME(jchlanda) Pauthtest does not support static linking. It must be dynamically linked, | |
| 202 | // with a dynamic linker acting as the ELF interpreter that can resolve pauth relocations | |
| 203 | // and enforce pointer authentication constraints. | |
| 204 | if tcx.sess.target.cfg_abi == CfgAbi::Pauthtest { | |
| 205 | if let NativeLibKind::Static { .. } = lib.kind { | |
| 206 | if !tcx.sess.opts.unstable_opts.ui_testing { | |
| 207 | let diag = if lib.foreign_module.is_none() { | |
| 208 | diagnostics::StaticLinkingNotSupported::UserRequested { | |
| 209 | lib_name: lib.name, | |
| 210 | target: tcx.sess.target.llvm_target.as_ref(), | |
| 211 | } | |
| 212 | } else { | |
| 213 | diagnostics::StaticLinkingNotSupported::FromDependency { | |
| 214 | lib_name: lib.name, | |
| 215 | target: tcx.sess.target.llvm_target.as_ref(), | |
| 216 | } | |
| 217 | }; | |
| 218 | tcx.dcx().emit_warn(diag); | |
| 219 | } | |
| 220 | ||
| 221 | lib.kind = NativeLibKind::Dylib { as_needed: None }; | |
| 222 | } | |
| 223 | } | |
| 224 | } | |
| 200 | 225 | collector.libs |
| 201 | 226 | } |
| 202 | 227 |
compiler/rustc_metadata/src/rmeta/encoder.rs+1-1| ... | ... | @@ -1624,7 +1624,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { |
| 1624 | 1624 | <- tcx.explicit_implied_const_bounds(def_id).skip_binder()); |
| 1625 | 1625 | } |
| 1626 | 1626 | } |
| 1627 | if let DefKind::AnonConst = def_kind { | |
| 1627 | if let DefKind::AnonConst | DefKind::InlineConst = def_kind { | |
| 1628 | 1628 | record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id)); |
| 1629 | 1629 | } |
| 1630 | 1630 | if should_encode_const_of_item(self.tcx, def_id, def_kind) { |
compiler/rustc_middle/src/hir/map.rs+7-8| ... | ... | @@ -22,7 +22,7 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, with_metavar_spans}; |
| 22 | 22 | use crate::hir::{ModuleItems, ProjectedMaybeOwner, nested_filter}; |
| 23 | 23 | use crate::middle::debugger_visualizer::DebuggerVisualizerFile; |
| 24 | 24 | use crate::query::{IntoQueryKey, LocalCrate}; |
| 25 | use crate::ty::TyCtxt; | |
| 25 | use crate::ty::{self, TyCtxt}; | |
| 26 | 26 | |
| 27 | 27 | /// An iterator that walks up the ancestor tree of a given `HirId`. |
| 28 | 28 | /// Constructed using `tcx.hir_parent_iter(hir_id)`. |
| ... | ... | @@ -879,13 +879,6 @@ impl<'tcx> TyCtxt<'tcx> { |
| 879 | 879 | self.hir_opt_delegation_info(delegation_id).expect("processing delegation") |
| 880 | 880 | } |
| 881 | 881 | |
| 882 | pub fn hir_is_delegation_child_segment(self, segment: &PathSegment<'_>) -> bool { | |
| 883 | let parent_def = self.hir_get_parent_item(segment.hir_id).def_id; | |
| 884 | ||
| 885 | self.hir_opt_delegation_info(parent_def) | |
| 886 | .is_some_and(|info| info.child_seg_id == segment.hir_id) | |
| 887 | } | |
| 888 | ||
| 889 | 882 | #[inline] |
| 890 | 883 | fn hir_opt_ident(self, id: HirId) -> Option<Ident> { |
| 891 | 884 | match self.hir_node(id) { |
| ... | ... | @@ -1115,6 +1108,12 @@ impl<'tcx> TyCtxt<'tcx> { |
| 1115 | 1108 | } |
| 1116 | 1109 | } |
| 1117 | 1110 | |
| 1111 | pub fn is_type_system_inline_const(self, def_id: impl IntoQueryKey<DefId>) -> bool { | |
| 1112 | let def_id = def_id.into_query_key(); | |
| 1113 | debug_assert_eq!(self.def_kind(def_id), DefKind::InlineConst); | |
| 1114 | self.anon_const_kind(def_id) != ty::AnonConstKind::NonTypeSystem | |
| 1115 | } | |
| 1116 | ||
| 1118 | 1117 | pub fn hir_maybe_get_struct_pattern_shorthand_field(self, expr: &Expr<'_>) -> Option<Symbol> { |
| 1119 | 1118 | let local = match expr { |
| 1120 | 1119 | Expr { |
compiler/rustc_middle/src/ty/context.rs+8-1| ... | ... | @@ -601,7 +601,14 @@ impl<'tcx> TyCtxt<'tcx> { |
| 601 | 601 | /// effect. However, we do not want this as a general capability, so this interface restricts |
| 602 | 602 | /// to the only allowed case. |
| 603 | 603 | pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx, Ty<'tcx>>) { |
| 604 | debug_assert_eq!(self.def_kind(key), DefKind::AnonConst); | |
| 604 | if cfg!(debug_assertions) { | |
| 605 | match self.def_kind(key) { | |
| 606 | DefKind::AnonConst => (), | |
| 607 | DefKind::InlineConst => assert!(self.is_type_system_inline_const(key)), | |
| 608 | def_kind => bug!("unexpected DefKind in feed_anon_const_type: {def_kind:?}"), | |
| 609 | } | |
| 610 | } | |
| 611 | ||
| 605 | 612 | TyCtxtFeed { tcx: self, key }.type_of(value) |
| 606 | 613 | } |
| 607 | 614 |
compiler/rustc_middle/src/ty/context/impl_interner.rs+4-3| ... | ... | @@ -244,7 +244,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 244 | 244 | DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy { def_id }, |
| 245 | 245 | DefKind::TyAlias => ty::AliasTermKind::FreeTy { def_id }, |
| 246 | 246 | DefKind::Const { .. } => ty::AliasTermKind::FreeConst { def_id }, |
| 247 | DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => { | |
| 247 | DefKind::AnonConst | DefKind::InlineConst | DefKind::Ctor(_, CtorKind::Const) => { | |
| 248 | 248 | ty::AliasTermKind::AnonConst { def_id } |
| 249 | 249 | } |
| 250 | 250 | kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), |
| ... | ... | @@ -541,8 +541,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 541 | 541 | // only want to consider types that *actually* unify with float/int vars. |
| 542 | 542 | fn for_each_relevant_impl<R: VisitorResult>( |
| 543 | 543 | self, |
| 544 | trait_def_id: DefId, | |
| 545 | self_ty: Ty<'tcx>, | |
| 544 | trait_ref: ty::TraitRef<'tcx>, | |
| 546 | 545 | mut f: impl FnMut(DefId) -> R, |
| 547 | 546 | ) -> R { |
| 548 | 547 | macro_rules! ret { |
| ... | ... | @@ -554,6 +553,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 554 | 553 | }; |
| 555 | 554 | } |
| 556 | 555 | |
| 556 | let trait_def_id = trait_ref.def_id; | |
| 557 | let self_ty = trait_ref.self_ty(); | |
| 557 | 558 | let tcx = self; |
| 558 | 559 | let trait_impls = tcx.trait_impls_of(trait_def_id); |
| 559 | 560 | let mut consider_impls_for_simplified_type = |simp| { |
compiler/rustc_middle/src/ty/util.rs+32-1| ... | ... | @@ -597,7 +597,38 @@ impl<'tcx> TyCtxt<'tcx> { |
| 597 | 597 | /// Returns `true` if `def_id` refers to a definition that does not have its own |
| 598 | 598 | /// type-checking context, i.e. closure, coroutine or inline const. |
| 599 | 599 | pub fn is_typeck_child(self, def_id: DefId) -> bool { |
| 600 | self.def_kind(def_id).is_typeck_child() | |
| 600 | match self.def_kind(def_id) { | |
| 601 | DefKind::InlineConst => !self.is_type_system_inline_const(def_id), | |
| 602 | DefKind::Closure | DefKind::SyntheticCoroutineBody => true, | |
| 603 | DefKind::Mod | |
| 604 | | DefKind::Struct | |
| 605 | | DefKind::Union | |
| 606 | | DefKind::Enum | |
| 607 | | DefKind::Variant | |
| 608 | | DefKind::Trait | |
| 609 | | DefKind::TyAlias | |
| 610 | | DefKind::ForeignTy | |
| 611 | | DefKind::TraitAlias | |
| 612 | | DefKind::AssocTy | |
| 613 | | DefKind::TyParam | |
| 614 | | DefKind::Fn | |
| 615 | | DefKind::Const { .. } | |
| 616 | | DefKind::ConstParam | |
| 617 | | DefKind::Static { .. } | |
| 618 | | DefKind::Ctor(_, _) | |
| 619 | | DefKind::AssocFn | |
| 620 | | DefKind::AssocConst { .. } | |
| 621 | | DefKind::Macro(_) | |
| 622 | | DefKind::ExternCrate | |
| 623 | | DefKind::Use | |
| 624 | | DefKind::ForeignMod | |
| 625 | | DefKind::AnonConst | |
| 626 | | DefKind::OpaqueTy | |
| 627 | | DefKind::Field | |
| 628 | | DefKind::LifetimeParam | |
| 629 | | DefKind::GlobalAsm | |
| 630 | | DefKind::Impl { .. } => false, | |
| 631 | } | |
| 601 | 632 | } |
| 602 | 633 | |
| 603 | 634 | /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). |
compiler/rustc_mir_transform/src/trivial_const.rs+4-5| ... | ... | @@ -52,11 +52,10 @@ where |
| 52 | 52 | F: FnOnce() -> B, |
| 53 | 53 | B: Deref<Target = Body<'tcx>>, |
| 54 | 54 | { |
| 55 | if !matches!( | |
| 56 | tcx.def_kind(def), | |
| 57 | DefKind::AssocConst { .. } | DefKind::Const { .. } | DefKind::AnonConst | |
| 58 | ) { | |
| 59 | return None; | |
| 55 | match tcx.def_kind(def) { | |
| 56 | DefKind::AssocConst { .. } | DefKind::Const { .. } | DefKind::AnonConst => (), | |
| 57 | DefKind::InlineConst if tcx.is_type_system_inline_const(def) => (), | |
| 58 | _ => return None, | |
| 60 | 59 | } |
| 61 | 60 | |
| 62 | 61 | // If there are impossible predicates then MIR passes will replace the body with |
compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs+17-21| ... | ... | @@ -539,28 +539,24 @@ where |
| 539 | 539 | candidates: &mut Vec<Candidate<I>>, |
| 540 | 540 | ) -> Result<(), RerunNonErased> { |
| 541 | 541 | let cx = self.cx(); |
| 542 | cx.for_each_relevant_impl( | |
| 543 | goal.predicate.trait_def_id(cx), | |
| 544 | goal.predicate.self_ty(), | |
| 545 | |impl_def_id| -> Result<_, _> { | |
| 546 | // For every `default impl`, there's always a non-default `impl` | |
| 547 | // that will *also* apply. There's no reason to register a candidate | |
| 548 | // for this impl, since it is *not* proof that the trait goal holds. | |
| 549 | if cx.impl_is_default(impl_def_id) { | |
| 550 | return Ok(()); | |
| 551 | } | |
| 552 | match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| { | |
| 553 | ecx.evaluate_added_goals_and_make_canonical_response(certainty) | |
| 554 | }) | |
| 555 | .map_err_to_rerun()? | |
| 556 | { | |
| 557 | Ok(candidate) => candidates.push(candidate), | |
| 558 | Err(NoSolution) => {} | |
| 559 | } | |
| 542 | cx.for_each_relevant_impl(goal.predicate.trait_ref(cx), |impl_def_id| -> Result<_, _> { | |
| 543 | // For every `default impl`, there's always a non-default `impl` | |
| 544 | // that will *also* apply. There's no reason to register a candidate | |
| 545 | // for this impl, since it is *not* proof that the trait goal holds. | |
| 546 | if cx.impl_is_default(impl_def_id) { | |
| 547 | return Ok(()); | |
| 548 | } | |
| 549 | match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| { | |
| 550 | ecx.evaluate_added_goals_and_make_canonical_response(certainty) | |
| 551 | }) | |
| 552 | .map_err_to_rerun()? | |
| 553 | { | |
| 554 | Ok(candidate) => candidates.push(candidate), | |
| 555 | Err(NoSolution) => {} | |
| 556 | } | |
| 560 | 557 | |
| 561 | Ok(()) | |
| 562 | }, | |
| 563 | ) | |
| 558 | Ok(()) | |
| 559 | }) | |
| 564 | 560 | } |
| 565 | 561 | |
| 566 | 562 | #[instrument(level = "trace", skip_all)] |
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+3-7| ... | ... | @@ -1246,13 +1246,9 @@ where |
| 1246 | 1246 | let self_ty = goal.predicate.self_ty(); |
| 1247 | 1247 | let check_impls = || { |
| 1248 | 1248 | let mut disqualifying_impl = None; |
| 1249 | self.cx().for_each_relevant_impl( | |
| 1250 | goal.predicate.def_id(), | |
| 1251 | goal.predicate.self_ty(), | |
| 1252 | |impl_def_id| { | |
| 1253 | disqualifying_impl = Some(impl_def_id); | |
| 1254 | }, | |
| 1255 | ); | |
| 1249 | self.cx().for_each_relevant_impl(goal.predicate.trait_ref, |impl_def_id| { | |
| 1250 | disqualifying_impl = Some(impl_def_id); | |
| 1251 | }); | |
| 1256 | 1252 | if let Some(def_id) = disqualifying_impl { |
| 1257 | 1253 | trace!(?def_id, ?goal, "disqualified auto-trait implementation"); |
| 1258 | 1254 | // No need to actually consider the candidate here, |
compiler/rustc_resolve/src/def_collector.rs+22-62| ... | ... | @@ -17,8 +17,7 @@ use tracing::{debug, instrument}; |
| 17 | 17 | |
| 18 | 18 | use crate::macros::MacroRulesScopeRef; |
| 19 | 19 | use crate::{ |
| 20 | ConstArgContext, ImplTraitContext, InvocationParent, ParentScope, Resolver, with_owner, | |
| 21 | with_owner_tables, | |
| 20 | ImplTraitContext, InvocationParent, ParentScope, Resolver, with_owner, with_owner_tables, | |
| 22 | 21 | }; |
| 23 | 22 | |
| 24 | 23 | pub(crate) fn collect_definitions<'ra>( |
| ... | ... | @@ -115,12 +114,6 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { |
| 115 | 114 | self.invocation_parent.impl_trait_context = orig_itc; |
| 116 | 115 | } |
| 117 | 116 | |
| 118 | fn with_const_arg<F: FnOnce(&mut Self)>(&mut self, ctxt: ConstArgContext, f: F) { | |
| 119 | let orig = mem::replace(&mut self.invocation_parent.const_arg_context, ctxt); | |
| 120 | f(self); | |
| 121 | self.invocation_parent.const_arg_context = orig; | |
| 122 | } | |
| 123 | ||
| 124 | 117 | fn collect_field(&mut self, field: &'a FieldDef, index: Option<usize>) { |
| 125 | 118 | let index = |this: &Self| { |
| 126 | 119 | index.unwrap_or_else(|| { |
| ... | ... | @@ -430,6 +423,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { |
| 430 | 423 | } |
| 431 | 424 | |
| 432 | 425 | fn visit_anon_const(&mut self, constant: &'a AnonConst) { |
| 426 | // Note that `visit_anon_const` is skipped for AnonConst nodes wrapped in an | |
| 427 | // ExprKind::ConstBlock - these are handled in visit_expr, and are DefKind::InlineConst. | |
| 428 | ||
| 433 | 429 | // `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so |
| 434 | 430 | // to avoid affecting stable we have to feature gate the not creating |
| 435 | 431 | // anon consts |
| ... | ... | @@ -441,16 +437,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { |
| 441 | 437 | } |
| 442 | 438 | |
| 443 | 439 | match constant.mgca_disambiguation { |
| 444 | MgcaDisambiguation::Direct => self.with_const_arg(ConstArgContext::Direct, |this| { | |
| 445 | visit::walk_anon_const(this, constant); | |
| 446 | }), | |
| 440 | MgcaDisambiguation::Direct => visit::walk_anon_const(self, constant), | |
| 447 | 441 | MgcaDisambiguation::AnonConst => { |
| 448 | self.with_const_arg(ConstArgContext::NonDirect, |this| { | |
| 449 | let parent = this | |
| 450 | .create_def(constant.id, None, DefKind::AnonConst, constant.value.span) | |
| 451 | .def_id(); | |
| 452 | this.with_parent(parent, |this| visit::walk_anon_const(this, constant)); | |
| 453 | }) | |
| 442 | let parent = self | |
| 443 | .create_def(constant.id, None, DefKind::AnonConst, constant.value.span) | |
| 444 | .def_id(); | |
| 445 | self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); | |
| 454 | 446 | } |
| 455 | 447 | }; |
| 456 | 448 | } |
| ... | ... | @@ -459,60 +451,28 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { |
| 459 | 451 | fn visit_expr(&mut self, expr: &'a Expr) { |
| 460 | 452 | debug!(?self.invocation_parent); |
| 461 | 453 | |
| 462 | let parent_def = match &expr.kind { | |
| 454 | match &expr.kind { | |
| 463 | 455 | ExprKind::MacCall(..) => { |
| 464 | 456 | self.visit_macro_invoc(expr.id); |
| 465 | 457 | self.visit_invoc(expr.id); |
| 466 | return; | |
| 467 | 458 | } |
| 468 | 459 | ExprKind::Closure(..) | ExprKind::Gen(..) => { |
| 469 | self.create_def(expr.id, None, DefKind::Closure, expr.span).def_id() | |
| 460 | let def = self.create_def(expr.id, None, DefKind::Closure, expr.span).def_id(); | |
| 461 | self.with_parent(def, |this| visit::walk_expr(this, expr)); | |
| 470 | 462 | } |
| 471 | 463 | ExprKind::ConstBlock(constant) => { |
| 472 | // Under `min_generic_const_args` a `const { }` block sometimes | |
| 473 | // corresponds to an anon const rather than an inline const. | |
| 474 | let def_kind = match self.invocation_parent.const_arg_context { | |
| 475 | ConstArgContext::Direct => DefKind::AnonConst, | |
| 476 | ConstArgContext::NonDirect => DefKind::InlineConst, | |
| 477 | }; | |
| 478 | ||
| 479 | return self.with_const_arg(ConstArgContext::NonDirect, |this| { | |
| 480 | for attr in &expr.attrs { | |
| 481 | visit::walk_attribute(this, attr); | |
| 482 | } | |
| 483 | ||
| 484 | let def = | |
| 485 | this.create_def(constant.id, None, def_kind, constant.value.span).def_id(); | |
| 486 | this.with_parent(def, |this| visit::walk_anon_const(this, constant)); | |
| 487 | }); | |
| 488 | } | |
| 489 | ||
| 490 | // Avoid overwriting `const_arg_context` as we may want to treat const blocks | |
| 491 | // as being anon consts if we are inside a const argument. | |
| 492 | ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) | ExprKind::Array(..) => { | |
| 493 | return visit::walk_expr(self, expr); | |
| 494 | } | |
| 495 | // FIXME(mgca): we may want to handle block labels in some manner | |
| 496 | ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind { | |
| 497 | // FIXME(mgca): this probably means that mac calls that expand | |
| 498 | // to semi'd const blocks are handled differently to just writing | |
| 499 | // out a semi'd const block. | |
| 500 | StmtKind::Expr(..) | StmtKind::MacCall(..) => return visit::walk_expr(self, expr), | |
| 501 | ||
| 502 | // Fallback to normal behaviour | |
| 503 | StmtKind::Let(..) | StmtKind::Item(..) | StmtKind::Semi(..) | StmtKind::Empty => { | |
| 504 | self.invocation_parent.parent_def | |
| 464 | for attr in &expr.attrs { | |
| 465 | visit::walk_attribute(self, attr); | |
| 505 | 466 | } |
| 506 | }, | |
| 507 | 467 | |
| 508 | _ => self.invocation_parent.parent_def, | |
| 509 | }; | |
| 510 | ||
| 511 | self.with_const_arg(ConstArgContext::NonDirect, |this| { | |
| 512 | // Note in some cases the `parent_def` here may be the existing parent | |
| 513 | // and this is actually a no-op `with_parent` call. | |
| 514 | this.with_parent(parent_def, |this| visit::walk_expr(this, expr)) | |
| 515 | }) | |
| 468 | let def = self | |
| 469 | .create_def(constant.id, None, DefKind::InlineConst, constant.value.span) | |
| 470 | .def_id(); | |
| 471 | // use specifically walk_anon_const, not walk_expr, to skip self.visit_anon_const | |
| 472 | self.with_parent(def, |this| visit::walk_anon_const(this, constant)); | |
| 473 | } | |
| 474 | _ => visit::walk_expr(self, expr), | |
| 475 | } | |
| 516 | 476 | } |
| 517 | 477 | |
| 518 | 478 | fn visit_ty(&mut self, ty: &'a Ty) { |
compiler/rustc_resolve/src/lib.rs-9| ... | ... | @@ -187,7 +187,6 @@ struct InvocationParent { |
| 187 | 187 | parent_def: LocalDefId, |
| 188 | 188 | impl_trait_context: ImplTraitContext, |
| 189 | 189 | in_attr: bool, |
| 190 | const_arg_context: ConstArgContext, | |
| 191 | 190 | owner: NodeId, |
| 192 | 191 | } |
| 193 | 192 | |
| ... | ... | @@ -196,7 +195,6 @@ impl InvocationParent { |
| 196 | 195 | parent_def: CRATE_DEF_ID, |
| 197 | 196 | impl_trait_context: ImplTraitContext::Existential, |
| 198 | 197 | in_attr: false, |
| 199 | const_arg_context: ConstArgContext::NonDirect, | |
| 200 | 198 | owner: CRATE_NODE_ID, |
| 201 | 199 | }; |
| 202 | 200 | } |
| ... | ... | @@ -208,13 +206,6 @@ enum ImplTraitContext { |
| 208 | 206 | InBinding, |
| 209 | 207 | } |
| 210 | 208 | |
| 211 | #[derive(Copy, Clone, Debug)] | |
| 212 | enum ConstArgContext { | |
| 213 | Direct, | |
| 214 | /// Either inside of an `AnonConst` or not inside a const argument at all. | |
| 215 | NonDirect, | |
| 216 | } | |
| 217 | ||
| 218 | 209 | /// Used for tracking import use types which will be used for redundant import checking. |
| 219 | 210 | /// |
| 220 | 211 | /// ### Used::Scope Example |
compiler/rustc_session/src/errors.rs+6| ... | ... | @@ -311,6 +311,12 @@ pub(crate) struct CannotMixAndMatchSanitizers { |
| 311 | 311 | )] |
| 312 | 312 | pub(crate) struct CannotEnableCrtStaticLinux; |
| 313 | 313 | |
| 314 | #[derive(Diagnostic)] | |
| 315 | #[diag( | |
| 316 | "pointer authentication requires dynamic linking. Statically linked libc is incompatible, disable it using `-C target-feature=-crt-static`" | |
| 317 | )] | |
| 318 | pub(crate) struct CannotEnableCrtStaticPointerAuth; | |
| 319 | ||
| 314 | 320 | #[derive(Diagnostic)] |
| 315 | 321 | #[diag("`-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`")] |
| 316 | 322 | pub(crate) struct SanitizerCfiRequiresLto; |
compiler/rustc_session/src/options.rs+1| ... | ... | @@ -2650,6 +2650,7 @@ options! { |
| 2650 | 2650 | "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), |
| 2651 | 2651 | profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], |
| 2652 | 2652 | "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"), |
| 2653 | ptrauth_elf_got: bool = (false, parse_bool, [TRACKED], "enable signing of ELF GOT entries"), | |
| 2653 | 2654 | query_dep_graph: bool = (false, parse_bool, [UNTRACKED], |
| 2654 | 2655 | "enable queries of the dependency graph for regression testing (default: no)"), |
| 2655 | 2656 | randomize_layout: bool = (false, parse_bool, [TRACKED], |
compiler/rustc_session/src/session.rs+10-3| ... | ... | @@ -29,9 +29,9 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; |
| 29 | 29 | use rustc_span::{RealFileName, Span, Symbol}; |
| 30 | 30 | use rustc_target::asm::InlineAsmArch; |
| 31 | 31 | use rustc_target::spec::{ |
| 32 | Arch, CodeModel, DebuginfoKind, Os, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, | |
| 33 | SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target, | |
| 34 | TargetTuple, TlsModel, apple, | |
| 32 | Arch, CfgAbi, CodeModel, DebuginfoKind, Os, PanicStrategy, RelocModel, RelroLevel, | |
| 33 | SanitizerSet, SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, | |
| 34 | Target, TargetTuple, TlsModel, apple, | |
| 35 | 35 | }; |
| 36 | 36 | |
| 37 | 37 | use crate::code_stats::CodeStats; |
| ... | ... | @@ -1229,6 +1229,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) { |
| 1229 | 1229 | sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux); |
| 1230 | 1230 | } |
| 1231 | 1231 | |
| 1232 | // FIXME(jchlanda) Pauthtest does not support static linking. It must be dynamically linked, | |
| 1233 | // with a dynamic linker acting as the ELF interpreter that can resolve pauth relocations and | |
| 1234 | // enforce pointer authentication constraints. | |
| 1235 | if sess.crt_static(None) && sess.target.cfg_abi == CfgAbi::Pauthtest { | |
| 1236 | sess.dcx().emit_err(errors::CannotEnableCrtStaticPointerAuth); | |
| 1237 | } | |
| 1238 | ||
| 1232 | 1239 | // LLVM CFI requires LTO. |
| 1233 | 1240 | if sess.is_sanitizer_cfi_enabled() |
| 1234 | 1241 | && !(sess.lto() == config::Lto::Fat || sess.opts.cg.linker_plugin_lto.enabled()) |
compiler/rustc_target/src/spec/mod.rs+9-3| ... | ... | @@ -1488,6 +1488,7 @@ supported_targets! { |
| 1488 | 1488 | ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), |
| 1489 | 1489 | ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), |
| 1490 | 1490 | ("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl), |
| 1491 | ("aarch64-unknown-linux-pauthtest", aarch64_unknown_linux_pauthtest), | |
| 1491 | 1492 | ("aarch64_be-unknown-linux-musl", aarch64_be_unknown_linux_musl), |
| 1492 | 1493 | ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), |
| 1493 | 1494 | ("i686-unknown-linux-musl", i686_unknown_linux_musl), |
| ... | ... | @@ -2072,6 +2073,7 @@ crate::target_spec_enum! { |
| 2072 | 2073 | Ilp32e = "ilp32e", |
| 2073 | 2074 | Llvm = "llvm", |
| 2074 | 2075 | MacAbi = "macabi", |
| 2076 | Pauthtest = "pauthtest", | |
| 2075 | 2077 | Sim = "sim", |
| 2076 | 2078 | SoftFloat = "softfloat", |
| 2077 | 2079 | Spe = "spe", |
| ... | ... | @@ -2112,6 +2114,8 @@ crate::target_spec_enum! { |
| 2112 | 2114 | // PowerPC |
| 2113 | 2115 | ElfV1 = "elfv1", |
| 2114 | 2116 | ElfV2 = "elfv2", |
| 2117 | // Pointer authentication: Pauthtest | |
| 2118 | Pauthtest = "pauthtest", | |
| 2115 | 2119 | |
| 2116 | 2120 | Unspecified = "", |
| 2117 | 2121 | } |
| ... | ... | @@ -3398,9 +3402,10 @@ impl Target { |
| 3398 | 3402 | ) |
| 3399 | 3403 | } |
| 3400 | 3404 | Arch::AArch64 => { |
| 3401 | check!( | |
| 3402 | self.llvm_abiname == LlvmAbi::Unspecified, | |
| 3403 | "`llvm_abiname` is unused on aarch64" | |
| 3405 | check_matches!( | |
| 3406 | self.llvm_abiname, | |
| 3407 | LlvmAbi::Unspecified | LlvmAbi::Pauthtest, | |
| 3408 | "invalid llvm ABI for aarch64" | |
| 3404 | 3409 | ); |
| 3405 | 3410 | check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on aarch64"); |
| 3406 | 3411 | // FIXME: Ensure that target_abi = "ilp32" correlates with actually using that ABI. |
| ... | ... | @@ -3413,6 +3418,7 @@ impl Target { |
| 3413 | 3418 | CfgAbi::Ilp32 |
| 3414 | 3419 | | CfgAbi::Llvm |
| 3415 | 3420 | | CfgAbi::MacAbi |
| 3421 | | CfgAbi::Pauthtest | |
| 3416 | 3422 | | CfgAbi::Sim |
| 3417 | 3423 | | CfgAbi::Uwp |
| 3418 | 3424 | | CfgAbi::Unspecified |
compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_pauthtest.rs created+38| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | use crate::spec::{ | |
| 2 | Arch, CfgAbi, Env, FramePointer, LinkSelfContainedDefault, LlvmAbi, StackProbeType, Target, | |
| 3 | TargetMetadata, TargetOptions, base, | |
| 4 | }; | |
| 5 | ||
| 6 | pub(crate) fn target() -> Target { | |
| 7 | Target { | |
| 8 | llvm_target: "aarch64-unknown-linux-pauthtest".into(), | |
| 9 | metadata: TargetMetadata { | |
| 10 | description: Some("ARM64 Linux with pauth enabled musl".into()), | |
| 11 | tier: Some(3), | |
| 12 | host_tools: Some(false), | |
| 13 | std: Some(false), | |
| 14 | }, | |
| 15 | pointer_width: 64, | |
| 16 | data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), | |
| 17 | arch: Arch::AArch64, | |
| 18 | ||
| 19 | options: TargetOptions { | |
| 20 | env: Env::Musl, | |
| 21 | cfg_abi: CfgAbi::Pauthtest, | |
| 22 | llvm_abiname: LlvmAbi::Pauthtest, | |
| 23 | // `pauthtest` requires v8.3a, which includes lse, no need for outline-atomics | |
| 24 | features: "+v8.3a,+pauth".into(), | |
| 25 | max_atomic_width: Some(128), | |
| 26 | stack_probes: StackProbeType::Inline, | |
| 27 | crt_static_default: false, | |
| 28 | crt_static_allows_dylibs: false, | |
| 29 | // the AAPCS64 expects use of non-leaf frame pointers per | |
| 30 | // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer | |
| 31 | // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not | |
| 32 | frame_pointer: FramePointer::NonLeaf, | |
| 33 | link_self_contained: LinkSelfContainedDefault::False, | |
| 34 | mcount: "\u{1}_mcount".into(), | |
| 35 | ..base::linux::opts() | |
| 36 | }, | |
| 37 | } | |
| 38 | } |
compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs+10| ... | ... | @@ -2556,6 +2556,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 2556 | 2556 | err.children.clear(); |
| 2557 | 2557 | |
| 2558 | 2558 | let mut span = obligation.cause.span; |
| 2559 | let mut is_async_fn_return = false; | |
| 2559 | 2560 | if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id) |
| 2560 | 2561 | && let parent = self.tcx.local_parent(obligation.cause.body_id) |
| 2561 | 2562 | && let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent) |
| ... | ... | @@ -2571,10 +2572,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 2571 | 2572 | // and |
| 2572 | 2573 | // async fn foo() -> dyn Display Box<dyn { .. }> |
| 2573 | 2574 | span = fn_sig.decl.output.span(); |
| 2575 | is_async_fn_return = true; | |
| 2574 | 2576 | err.span(span); |
| 2575 | 2577 | } |
| 2576 | 2578 | let body = self.tcx.hir_body_owned_by(obligation.cause.body_id); |
| 2577 | 2579 | |
| 2580 | if !is_async_fn_return | |
| 2581 | && let Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = | |
| 2582 | self.tcx.hir_node_by_def_id(obligation.cause.body_id) | |
| 2583 | && matches!(closure.fn_decl.output, hir::FnRetTy::DefaultReturn(_)) | |
| 2584 | { | |
| 2585 | return true; | |
| 2586 | } | |
| 2587 | ||
| 2578 | 2588 | let mut visitor = ReturnsVisitor::default(); |
| 2579 | 2589 | visitor.visit_body(&body); |
| 2580 | 2590 |
compiler/rustc_ty_utils/src/opaque_types.rs+9-8| ... | ... | @@ -317,6 +317,10 @@ fn opaque_types_defined_by<'tcx>( |
| 317 | 317 | tcx: TyCtxt<'tcx>, |
| 318 | 318 | item: LocalDefId, |
| 319 | 319 | ) -> &'tcx ty::List<LocalDefId> { |
| 320 | // Closures and coroutines are type checked with their parent | |
| 321 | // Note that we also support `SyntheticCoroutineBody` since we create | |
| 322 | // a MIR body for the def kind, and some MIR passes (like promotion) | |
| 323 | // may require doing analysis using its typing env. | |
| 320 | 324 | if tcx.is_typeck_child(item.to_def_id()) { |
| 321 | 325 | return tcx.opaque_types_defined_by(tcx.local_parent(item)); |
| 322 | 326 | } |
| ... | ... | @@ -332,7 +336,11 @@ fn opaque_types_defined_by<'tcx>( |
| 332 | 336 | | DefKind::Static { .. } |
| 333 | 337 | | DefKind::Const { .. } |
| 334 | 338 | | DefKind::AssocConst { .. } |
| 335 | | DefKind::AnonConst => { | |
| 339 | | DefKind::AnonConst | |
| 340 | | DefKind::InlineConst => { | |
| 341 | // Non-type-system inline consts should be caught by `if tcx.is_typeck_child` above | |
| 342 | debug_assert!(kind != DefKind::InlineConst || tcx.is_type_system_inline_const(item)); | |
| 343 | ||
| 336 | 344 | collector.collect_taits_declared_in_body(); |
| 337 | 345 | } |
| 338 | 346 | DefKind::AssocTy | DefKind::TyAlias | DefKind::GlobalAsm => {} |
| ... | ... | @@ -345,15 +353,8 @@ fn opaque_types_defined_by<'tcx>( |
| 345 | 353 | | DefKind::Trait |
| 346 | 354 | | DefKind::ForeignTy |
| 347 | 355 | | DefKind::TraitAlias |
| 348 | ||
| 349 | // Closures and coroutines are type checked with their parent | |
| 350 | // Note that we also support `SyntheticCoroutineBody` since we create | |
| 351 | // a MIR body for the def kind, and some MIR passes (like promotion) | |
| 352 | // may require doing analysis using its typing env. | |
| 353 | 356 | | DefKind::Closure |
| 354 | | DefKind::InlineConst | |
| 355 | 357 | | DefKind::SyntheticCoroutineBody |
| 356 | ||
| 357 | 358 | | DefKind::TyParam |
| 358 | 359 | | DefKind::ConstParam |
| 359 | 360 | | DefKind::Ctor(_, _) |
compiler/rustc_ty_utils/src/sig_types.rs+20-18| ... | ... | @@ -21,6 +21,24 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( |
| 21 | 21 | ) -> V::Result { |
| 22 | 22 | let kind = tcx.def_kind(item); |
| 23 | 23 | trace!(?kind); |
| 24 | let mut visit_alias = || { | |
| 25 | if let Some(ty) = tcx.hir_node_by_def_id(item).ty() { | |
| 26 | // If the type of the item uses `_`, we're gonna error out anyway, but | |
| 27 | // typeck (which type_of invokes below), will call back into opaque_types_defined_by | |
| 28 | // causing a cycle. So we just bail out in this case. | |
| 29 | if ty.is_suggestable_infer_ty() { | |
| 30 | return V::Result::output(); | |
| 31 | } | |
| 32 | // Associated types in traits don't necessarily have a type that we can visit | |
| 33 | try_visit!( | |
| 34 | visitor.visit(ty.span, tcx.type_of(item).instantiate_identity().skip_norm_wip()) | |
| 35 | ); | |
| 36 | } | |
| 37 | for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { | |
| 38 | try_visit!(visitor.visit(span, pred.skip_norm_wip())); | |
| 39 | } | |
| 40 | V::Result::output() | |
| 41 | }; | |
| 24 | 42 | match kind { |
| 25 | 43 | // Walk over the signature of the function |
| 26 | 44 | DefKind::AssocFn | DefKind::Fn => { |
| ... | ... | @@ -47,24 +65,8 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( |
| 47 | 65 | | DefKind::Static { .. } |
| 48 | 66 | | DefKind::Const { .. } |
| 49 | 67 | | DefKind::AssocConst { .. } |
| 50 | | DefKind::AnonConst => { | |
| 51 | if let Some(ty) = tcx.hir_node_by_def_id(item).ty() { | |
| 52 | // If the type of the item uses `_`, we're gonna error out anyway, but | |
| 53 | // typeck (which type_of invokes below), will call back into opaque_types_defined_by | |
| 54 | // causing a cycle. So we just bail out in this case. | |
| 55 | if ty.is_suggestable_infer_ty() { | |
| 56 | return V::Result::output(); | |
| 57 | } | |
| 58 | // Associated types in traits don't necessarily have a type that we can visit | |
| 59 | try_visit!( | |
| 60 | visitor | |
| 61 | .visit(ty.span, tcx.type_of(item).instantiate_identity().skip_norm_wip()) | |
| 62 | ); | |
| 63 | } | |
| 64 | for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { | |
| 65 | try_visit!(visitor.visit(span, pred.skip_norm_wip())); | |
| 66 | } | |
| 67 | } | |
| 68 | | DefKind::AnonConst => return visit_alias(), | |
| 69 | DefKind::InlineConst if tcx.is_type_system_inline_const(item) => return visit_alias(), | |
| 68 | 70 | DefKind::OpaqueTy => { |
| 69 | 71 | for (pred, span) in tcx |
| 70 | 72 | .explicit_item_bounds(item) |
compiler/rustc_type_ir/src/interner.rs+2-3| ... | ... | @@ -16,7 +16,7 @@ use crate::solve::{ |
| 16 | 16 | AccessedOpaques, CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect, |
| 17 | 17 | }; |
| 18 | 18 | use crate::visit::{Flags, TypeVisitable}; |
| 19 | use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph}; | |
| 19 | use crate::{self as ty, CanonicalParamEnvCacheEntry, TraitRef, search_graph}; | |
| 20 | 20 | |
| 21 | 21 | #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_interner")] |
| 22 | 22 | pub trait Interner: |
| ... | ... | @@ -398,8 +398,7 @@ pub trait Interner: |
| 398 | 398 | |
| 399 | 399 | fn for_each_relevant_impl<R: VisitorResult>( |
| 400 | 400 | self, |
| 401 | trait_def_id: Self::TraitId, | |
| 402 | self_ty: Self::Ty, | |
| 401 | trait_ref: TraitRef<Self>, | |
| 403 | 402 | f: impl FnMut(Self::ImplId) -> R, |
| 404 | 403 | ) -> R; |
| 405 | 404 | fn for_each_blanket_impl<R: VisitorResult>( |
library/alloc/src/io/error.rs+3| ... | ... | @@ -55,6 +55,7 @@ impl Error { |
| 55 | 55 | /// originate from the OS itself. It is a shortcut for [`Error::new`][new] |
| 56 | 56 | /// with [`ErrorKind::Other`]. |
| 57 | 57 | /// |
| 58 | // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method | |
| 58 | 59 | /// [new]: struct.Error.html#method.new |
| 59 | 60 | /// |
| 60 | 61 | /// # Examples |
| ... | ... | @@ -84,6 +85,7 @@ impl Error { |
| 84 | 85 | /// then this function will return [`Some`], |
| 85 | 86 | /// otherwise it will return [`None`]. |
| 86 | 87 | /// |
| 88 | // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method | |
| 87 | 89 | /// [new]: struct.Error.html#method.new |
| 88 | 90 | /// [other]: struct.Error.html#method.other |
| 89 | 91 | /// |
| ... | ... | @@ -141,6 +143,7 @@ impl Error { |
| 141 | 143 | /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by |
| 142 | 144 | /// [`Error::into_inner`][into_inner]. |
| 143 | 145 | /// |
| 146 | // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method | |
| 144 | 147 | /// [into_inner]: struct.Error.html#method.into_inner |
| 145 | 148 | /// |
| 146 | 149 | /// # Examples |
library/core/src/io/cursor.rs+2| ... | ... | @@ -16,6 +16,7 @@ |
| 16 | 16 | /// code, but use an in-memory buffer in our tests. We can do this with |
| 17 | 17 | /// `Cursor`: |
| 18 | 18 | /// |
| 19 | // FIXME(#74481): Hard-links required to link from `core` to `std` | |
| 19 | 20 | /// [bytes]: crate::slice "slice" |
| 20 | 21 | /// [`File`]: ../../std/fs/struct.File.html |
| 21 | 22 | /// [`Read`]: ../../std/io/trait.Read.html |
| ... | ... | @@ -80,6 +81,7 @@ impl<T> Cursor<T> { |
| 80 | 81 | /// is not empty. So writing to cursor starts with overwriting [`Vec`] |
| 81 | 82 | /// content, not with appending to it. |
| 82 | 83 | /// |
| 84 | // FIXME(#74481): Hard-links required to link from `core` to `alloc` | |
| 83 | 85 | /// [`Vec`]: ../../alloc/vec/struct.Vec.html |
| 84 | 86 | /// |
| 85 | 87 | /// # Examples |
library/core/src/io/error.rs+6| ... | ... | @@ -45,6 +45,7 @@ use crate::{error, fmt, result}; |
| 45 | 45 | /// will generally use `io::Result` instead of shadowing the [prelude]'s import |
| 46 | 46 | /// of [`core::result::Result`][`Result`]. |
| 47 | 47 | /// |
| 48 | // FIXME(#74481): Hard-links required to link from `core` to `std` | |
| 48 | 49 | /// [`std::io`]: ../../std/io/index.html |
| 49 | 50 | /// [`io::Error`]: Error |
| 50 | 51 | /// [`Result`]: crate::result::Result |
| ... | ... | @@ -76,6 +77,7 @@ pub type Result<T> = result::Result<T, Error>; |
| 76 | 77 | /// `Error` can be created with crafted error messages and a particular value of |
| 77 | 78 | /// [`ErrorKind`]. |
| 78 | 79 | /// |
| 80 | // FIXME(#74481): Hard-links required to link from `core` to `std` | |
| 79 | 81 | /// [Read]: ../../std/io/trait.Read.html |
| 80 | 82 | /// [Write]: ../../std/io/trait.Write.html |
| 81 | 83 | /// [Seek]: ../../std/io/trait.Seek.html |
| ... | ... | @@ -171,6 +173,7 @@ pub struct SimpleMessage { |
| 171 | 173 | /// Contrary to [`Error::new`][new], this macro does not allocate and can be used in |
| 172 | 174 | /// `const` contexts. |
| 173 | 175 | /// |
| 176 | // FIXME(#74481): Hard-links required to link from `core` to `alloc` for incoherent method | |
| 174 | 177 | /// [new]: ../../alloc/io/struct.Error.html#method.new |
| 175 | 178 | /// |
| 176 | 179 | /// # Example |
| ... | ... | @@ -286,6 +289,7 @@ impl Error { |
| 286 | 289 | /// [`from_raw_os_error`][from_raw_os_error], then this function will return [`Some`], otherwise |
| 287 | 290 | /// it will return [`None`]. |
| 288 | 291 | /// |
| 292 | // FIXME(#74481): Hard-links required to link from `core` to `std` for incoherent method | |
| 289 | 293 | /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error |
| 290 | 294 | /// [from_raw_os_error]: ../../std/io/struct.Error.html#method.from_raw_os_error |
| 291 | 295 | /// |
| ... | ... | @@ -366,6 +370,7 @@ impl Error { |
| 366 | 370 | /// If this [`Error`] was constructed via [`new`][new] then this function will |
| 367 | 371 | /// return [`Some`], otherwise it will return [`None`]. |
| 368 | 372 | /// |
| 373 | // FIXME(#74481): Hard-links required to link from `core` to `std` | |
| 369 | 374 | /// [new]: ../../alloc/io/struct.Error.html#method.new |
| 370 | 375 | /// |
| 371 | 376 | /// # Examples |
| ... | ... | @@ -441,6 +446,7 @@ impl Error { |
| 441 | 446 | /// it will be a value inferred from the system's error encoding. |
| 442 | 447 | /// See [`last_os_error`][last_os_error] for more details. |
| 443 | 448 | /// |
| 449 | // FIXME(#74481): Hard-links required to link from `core` to `std` | |
| 444 | 450 | /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error |
| 445 | 451 | /// |
| 446 | 452 | /// # Examples |
src/bootstrap/src/core/build_steps/test.rs+52-23| ... | ... | @@ -10,6 +10,7 @@ use std::collections::HashSet; |
| 10 | 10 | use std::env::split_paths; |
| 11 | 11 | use std::ffi::{OsStr, OsString}; |
| 12 | 12 | use std::path::{Path, PathBuf}; |
| 13 | use std::process::Command; | |
| 13 | 14 | use std::{env, fs, iter}; |
| 14 | 15 | |
| 15 | 16 | use build_helper::exit; |
| ... | ... | @@ -2474,7 +2475,13 @@ Please disable assertions with `rust.debug-assertions = false`. |
| 2474 | 2475 | "-Lnative={}", |
| 2475 | 2476 | builder.test_helpers_out(test_compiler.host).display() |
| 2476 | 2477 | )); |
| 2477 | targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); | |
| 2478 | let target_helpers = builder.test_helpers_out(target); | |
| 2479 | targetflags.push(format!("-Lnative={}", target_helpers.display())); | |
| 2480 | if target.is_pauthtest() { | |
| 2481 | // For the pauthtest target, embed an rpath to the directory containing the helper | |
| 2482 | // dynamic library. | |
| 2483 | targetflags.push(format!("-Clink-arg=-Wl,-rpath,{}", target_helpers.display())); | |
| 2484 | } | |
| 2478 | 2485 | } |
| 2479 | 2486 | |
| 2480 | 2487 | for flag in hostflags { |
| ... | ... | @@ -4120,32 +4127,54 @@ impl Step for TestHelpers { |
| 4120 | 4127 | }; |
| 4121 | 4128 | let dst = builder.test_helpers_out(target); |
| 4122 | 4129 | let src = builder.src.join("tests/auxiliary/rust_test_helpers.c"); |
| 4123 | if up_to_date(&src, &dst.join("librust_test_helpers.a")) { | |
| 4124 | return; | |
| 4125 | } | |
| 4126 | ||
| 4127 | 4130 | let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target); |
| 4128 | 4131 | t!(fs::create_dir_all(&dst)); |
| 4129 | let mut cfg = cc::Build::new(); | |
| 4130 | 4132 | |
| 4131 | // We may have found various cross-compilers a little differently due to our | |
| 4132 | // extra configuration, so inform cc of these compilers. Note, though, that | |
| 4133 | // on MSVC we still need cc's detection of env vars (ugh). | |
| 4134 | if !target.is_msvc() { | |
| 4135 | if let Some(ar) = builder.ar(target) { | |
| 4136 | cfg.archiver(ar); | |
| 4133 | if !up_to_date(&src, &dst.join("librust_test_helpers.a")) { | |
| 4134 | let mut cfg = cc::Build::new(); | |
| 4135 | ||
| 4136 | // We may have found various cross-compilers a little differently due to our | |
| 4137 | // extra configuration, so inform cc of these compilers. Note, though, that | |
| 4138 | // on MSVC we still need cc's detection of env vars (ugh). | |
| 4139 | if !target.is_msvc() { | |
| 4140 | if let Some(ar) = builder.ar(target) { | |
| 4141 | cfg.archiver(ar); | |
| 4142 | } | |
| 4143 | cfg.compiler(builder.cc(target)); | |
| 4144 | } | |
| 4145 | cfg.cargo_metadata(false) | |
| 4146 | .out_dir(&dst) | |
| 4147 | .target(&target.triple) | |
| 4148 | .host(&builder.config.host_target.triple) | |
| 4149 | .opt_level(0) | |
| 4150 | .warnings(false) | |
| 4151 | .debug(false) | |
| 4152 | .file(builder.src.join("tests/auxiliary/rust_test_helpers.c")) | |
| 4153 | .compile("rust_test_helpers"); | |
| 4154 | } | |
| 4155 | if target.is_pauthtest() { | |
| 4156 | let so = dst.join("librust_test_helpers.so"); | |
| 4157 | if up_to_date(&src, &so) { | |
| 4158 | return; | |
| 4137 | 4159 | } |
| 4138 | cfg.compiler(builder.cc(target)); | |
| 4139 | } | |
| 4140 | cfg.cargo_metadata(false) | |
| 4141 | .out_dir(&dst) | |
| 4142 | .target(&target.triple) | |
| 4143 | .host(&builder.config.host_target.triple) | |
| 4144 | .opt_level(0) | |
| 4145 | .warnings(false) | |
| 4146 | .debug(false) | |
| 4147 | .file(builder.src.join("tests/auxiliary/rust_test_helpers.c")) | |
| 4148 | .compile("rust_test_helpers"); | |
| 4160 | ||
| 4161 | let status = Command::new(builder.cc(target)) | |
| 4162 | .arg("-target") | |
| 4163 | .arg(target.triple) | |
| 4164 | .arg("-march=armv8.3-a+pauth") | |
| 4165 | .arg("-fPIC") | |
| 4166 | .arg("-shared") | |
| 4167 | .arg("-O0") // Use O0 to match what static library is compiled at. | |
| 4168 | .arg("-o") | |
| 4169 | .arg(&so) | |
| 4170 | .arg(&src) | |
| 4171 | .status() | |
| 4172 | .unwrap_or_else(|_| panic!("Failed to run clang for {} toolchain", target.triple)); | |
| 4173 | ||
| 4174 | if !status.success() { | |
| 4175 | panic!("Linking of librust_test_helpers.so failed (target: {})", target.triple); | |
| 4176 | } | |
| 4177 | } | |
| 4149 | 4178 | } |
| 4150 | 4179 | } |
| 4151 | 4180 |
src/bootstrap/src/core/config/target_selection.rs+4| ... | ... | @@ -78,6 +78,10 @@ impl TargetSelection { |
| 78 | 78 | self.contains("msvc") |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | pub fn is_pauthtest(&self) -> bool { | |
| 82 | self.contains("pauthtest") | |
| 83 | } | |
| 84 | ||
| 81 | 85 | pub fn is_windows(&self) -> bool { |
| 82 | 86 | self.contains("windows") |
| 83 | 87 | } |
src/bootstrap/src/core/sanity.rs+49-1| ... | ... | @@ -21,7 +21,7 @@ use crate::builder::Kind; |
| 21 | 21 | use crate::core::build_steps::tool; |
| 22 | 22 | use crate::core::config::{CompilerBuiltins, Target}; |
| 23 | 23 | use crate::utils::exec::command; |
| 24 | use crate::{Build, Subcommand}; | |
| 24 | use crate::{Build, Subcommand, t}; | |
| 25 | 25 | |
| 26 | 26 | pub struct Finder { |
| 27 | 27 | cache: HashMap<OsString, Option<PathBuf>>, |
| ... | ... | @@ -38,6 +38,7 @@ pub struct Finder { |
| 38 | 38 | const STAGE0_MISSING_TARGETS: &[&str] = &[ |
| 39 | 39 | // just a dummy comment so the list doesn't get onelined |
| 40 | 40 | "powerpc64-unknown-linux-gnuelfv2", |
| 41 | "aarch64-unknown-linux-pauthtest", // Stage 0 compiler is not guaranteed to see the target yet. | |
| 41 | 42 | ]; |
| 42 | 43 | |
| 43 | 44 | /// Minimum version threshold for libstdc++ required when using prebuilt LLVM |
| ... | ... | @@ -412,6 +413,53 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake |
| 412 | 413 | { |
| 413 | 414 | cmd_finder.must_have("wasm-component-ld"); |
| 414 | 415 | } |
| 416 | ||
| 417 | // aarch64-unknown-linux-pauthtest must use clang | |
| 418 | if !skip_tools_checks && target.is_pauthtest() { | |
| 419 | let cc_tool = build.cc_tool(*target); | |
| 420 | let linker_path = build | |
| 421 | .linker(*target) | |
| 422 | .unwrap_or_else(|| panic!("{} requires an explicit clang linker", target.triple)); | |
| 423 | ||
| 424 | if !cc_tool.is_like_clang() { | |
| 425 | panic!( | |
| 426 | "Clang is required to build C code for {} target, got:\n\ | |
| 427 | cc tool: `{}`,\n\ | |
| 428 | linker: `{}`\n", | |
| 429 | target.triple, | |
| 430 | cc_tool.path().display(), | |
| 431 | linker_path.display(), | |
| 432 | ); | |
| 433 | } | |
| 434 | let cc_canon = t!(fs::canonicalize(cc_tool.path())); | |
| 435 | let linker_canon = t!(fs::canonicalize(&linker_path)); | |
| 436 | if cc_canon != linker_canon { | |
| 437 | panic!( | |
| 438 | "CC and Linker are expected to be the same for {} target, got:\n\ | |
| 439 | CC: `{}`,\n\ | |
| 440 | Linker: `{}`\n", | |
| 441 | target.triple, | |
| 442 | cc_canon.display(), | |
| 443 | linker_canon.display(), | |
| 444 | ); | |
| 445 | } | |
| 446 | ||
| 447 | let output = | |
| 448 | command(cc_tool.path()).arg("-dumpversion").run_capture_stdout(&build).stdout(); | |
| 449 | let version_str = output.trim(); | |
| 450 | let mut parts = version_str.split('.').map(|s| s.parse::<u32>().unwrap_or(0)); | |
| 451 | let major = parts.next().unwrap_or(0); | |
| 452 | let minor = parts.next().unwrap_or(0); | |
| 453 | let patch = parts.next().unwrap_or(0); | |
| 454 | if (major, minor, patch) < (22, 1, 0) { | |
| 455 | panic!( | |
| 456 | "clang version too old: {} ({} target trequires >= 22.1.0), path: {}", | |
| 457 | target.triple, | |
| 458 | version_str, | |
| 459 | cc_tool.path().display() | |
| 460 | ); | |
| 461 | } | |
| 462 | } | |
| 415 | 463 | } |
| 416 | 464 | |
| 417 | 465 | if let Some(ref s) = build.config.ccache { |
src/doc/rustc/src/SUMMARY.md+1| ... | ... | @@ -49,6 +49,7 @@ |
| 49 | 49 | - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) |
| 50 | 50 | - [aarch64-unknown-linux-gnu](platform-support/aarch64-unknown-linux-gnu.md) |
| 51 | 51 | - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md) |
| 52 | - [aarch64-unknown-linux-pauthtest](platform-support/aarch64-unknown-linux-pauthtest.md) | |
| 52 | 53 | - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md) |
| 53 | 54 | - [aarch64v8r-unknown-none*](platform-support/aarch64v8r-unknown-none.md) |
| 54 | 55 | - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) |
src/doc/rustc/src/platform-support.md+1| ... | ... | @@ -271,6 +271,7 @@ target | std | host | notes |
| 271 | 271 | [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit |
| 272 | 272 | [`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos |
| 273 | 273 | `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) |
| 274 | [`aarch64-unknown-linux-pauthtest`](platform-support/aarch64-unknown-linux-pauthtest.md) | ✓ | ✓ | ARM64 PAC ELF ABI | |
| 274 | 275 | [`aarch64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | ARM64 Managarm |
| 275 | 276 | [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD |
| 276 | 277 | [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | |
src/doc/rustc/src/platform-support/aarch64-unknown-linux-pauthtest.md created+440| ... | ... | @@ -0,0 +1,440 @@ |
| 1 | # aarch64-unknown-linux-pauthtest | |
| 2 | ||
| 3 | **Tier: 3** | |
| 4 | ||
| 5 | This target enables Pointer Authentication Code (PAC) support in Rust on AArch64 | |
| 6 | ELF-based Linux systems. It uses the `aarch64-unknown-linux-pauthtest` LLVM | |
| 7 | target and a pointer-authentication-enabled sysroot with a custom musl as a | |
| 8 | reference libc implementation. Dynamic linking is required, with a dynamic | |
| 9 | linker acting as the ELF interpreter that can resolve pauth relocations and | |
| 10 | enforce pointer authentication constraints. | |
| 11 | ||
| 12 | Supported features include: | |
| 13 | * authentication of signed function pointers for extern "C" calls (corresponds | |
| 14 | to LLVM's `-fptrauth-calls`) | |
| 15 | * signing of return addresses before spilling to the stack and authentication | |
| 16 | after restoring for non-leaf functions (corresponds to `-fptrauth-returns`) | |
| 17 | * trapping on authentication failure when the FPAC feature is not present | |
| 18 | (corresponds to `-fptrauth-auth-traps`) | |
| 19 | * signing of init/fini array entries using the LLVM-defined pointer | |
| 20 | authentication scheme (corresponds to `-fptrauth-init-fini` and | |
| 21 | `-fptrauth-init-fini-address-discrimination`) | |
| 22 | * non-ABI-affecting indirect control-flow hardening features as implemented in | |
| 23 | LLVM (corresponds to `-faarch64-jump-table-hardening` and | |
| 24 | `-fptrauth-indirect-gotos`) | |
| 25 | * signed ELF GOT entries (gated behind `-Z ptrauth-elf-got`, off by default) | |
| 26 | ||
| 27 | A tracking issue for adding support for the AArch64 pointer authentication ABI | |
| 28 | in Rust can be found at | |
| 29 | [#148640](https://github.com/rust-lang/rust/issues/148640). | |
| 30 | ||
| 31 | Existing compiler support, such as enabling branch authentication instructions | |
| 32 | (i.e.: `-Z branch-protection`) provide limited functionality, mainly signing | |
| 33 | return addresses (`pac-ret`). The new target goes further by enabling ABI-level | |
| 34 | pointer authentication support. | |
| 35 | ||
| 36 | This target does not define a new ABI; it builds on the existing C/C++ language | |
| 37 | ABI with pointer authentication support added. However, different authentication | |
| 38 | features, encoded in the signing schema, are not ABI-compatible with one | |
| 39 | another. | |
| 40 | ||
| 41 | Useful links: | |
| 42 | * Clang pointer authentication documentation: | |
| 43 | https://clang.llvm.org/docs/PointerAuthentication.html | |
| 44 | * LLVM pointer authentication documentation: | |
| 45 | https://llvm.org/docs/PointerAuth.html | |
| 46 | * PAuth ABI Extension to ELF for the AArch64 architecture: | |
| 47 | https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst | |
| 48 | ||
| 49 | ## Target maintainers | |
| 50 | ||
| 51 | [@jchlanda](https://github.com/jchlanda) | |
| 52 | ||
| 53 | ## Requirements | |
| 54 | ||
| 55 | This target supports cross-compilation from any Linux host, but execution | |
| 56 | requires AArch64 with pointer authentication support (ARMv8.3-A or higher). | |
| 57 | ||
| 58 | ## Standard library support | |
| 59 | ||
| 60 | Full std support is available: `core`, `alloc`, and `std` all build | |
| 61 | successfully. All library tests (`core`, `alloc`, `std`) pass for this target as | |
| 62 | well. | |
| 63 | ||
| 64 | ## Building the toolchain | |
| 65 | ||
| 66 | Building this target requires a pointer-authentication-enabled sysroot based on | |
| 67 | a custom musl toolchain. The sysroot must be available on the system before | |
| 68 | compilation. To build it, follow the instructions in the [build scripts | |
| 69 | repo](https://github.com/access-softek/pauth-toolchain-build-scripts). | |
| 70 | ||
| 71 | The target uses Clang, please make sure it is `v22.1.0` or higher. When using a | |
| 72 | system-provided Clang, a compiler wrapper is required to supply the necessary | |
| 73 | flags. Please consult the listing: | |
| 74 | ||
| 75 | ```sh | |
| 76 | #!/usr/bin/env sh | |
| 77 | ||
| 78 | clang \ | |
| 79 | -target aarch64-unknown-linux-pauthtest \ | |
| 80 | -march=armv8.3-a+pauth \ | |
| 81 | --sysroot <toolchain_root>/aarch64-linux-pauthtest/usr \ | |
| 82 | -resource-dir <toolchain_root>/lib/clang/<version> \ | |
| 83 | --rtlib=compiler-rt \ | |
| 84 | --ld-path=/usr/bin/ld.lld \ | |
| 85 | --unwindlib=libunwind \ | |
| 86 | -Wl,--dynamic-linker=<toolchain_root>/aarch64-linux-pauthtest/usr/lib/libc.so \ | |
| 87 | -Wl,--rpath=<toolchain_root>/aarch64-linux-pauthtest/usr/lib \ | |
| 88 | "$@" | |
| 89 | ``` | |
| 90 | ||
| 91 | Bootstrap validates the name of the configured C compiler, so when using a | |
| 92 | wrapper its name must contain `clang`. A recommended name is | |
| 93 | `aarch64-unknown-linux-pauthtest-clang`. Update the script to set `--sysroot`, | |
| 94 | `-resource-dir`, `--dynamic-linker` and `--rpath` correctly by replacing | |
| 95 | `<toolchain_root>` with the directory produced by the build scripts and the | |
| 96 | `<version>` with LLVM's version. Make the wrapper executable. | |
| 97 | ||
| 98 | To verify that the toolchain layout is correct, check that: | |
| 99 | * the sysroot contains a pointer-authentication-enabled version of libunwind | |
| 100 | (`<toolchain_root>/aarch64-linux-pauthtest/usr/lib/libunwind.so`), | |
| 101 | * the Clang resource directory contains the appropriate `compiler-rt` objects | |
| 102 | (`<toolchain_root>/lib/clang/<version>/lib/aarch64-unknown-linux-pauthtest/{clang_rt.crtbegin.o,clang_rt.crtend.o}`) | |
| 103 | ||
| 104 | When using the AccessSoftek scripts to build the sysroot, the result includes a | |
| 105 | Clang-based toolchain. In this case, no wrapper script is required, | |
| 106 | `<toolchain_root>/bin/aarch64-linux-pauthtest-clang` can be used directly. | |
| 107 | ||
| 108 | ## Building the target | |
| 109 | ||
| 110 | Introduction of `aarch64-unknown-linux-pauthtest` target needs to be propagated | |
| 111 | to various crates/repos, so that they can correctly recognise and handle it. | |
| 112 | Specifically: | |
| 113 | * `cc-rs`: https://github.com/jchlanda/cc-rs/tree/jakub/cc-v1.2.28-pauthtest | |
| 114 | * `libc`: https://github.com/jchlanda/libc/tree/jakub/0.2.183-pauthtest | |
| 115 | * `backtrace`: https://github.com/jchlanda/backtrace-rs/tree/jakub/backtrace-v0.3.76-pauthtest | |
| 116 | ||
| 117 | The patched versions of `cc-rs` and `libc` will have to be registered through | |
| 118 | `[patch.crates-io]` section of `Cargo.toml` files both in: | |
| 119 | `<rust_root>/src/bootstrap/` and `<rust_root>/library/`. Check out `cc-rs` and | |
| 120 | `libc` to `<rust_root>/patches` and update config files. See attached diff for | |
| 121 | details: | |
| 122 | ||
| 123 | <details> | |
| 124 | ||
| 125 | ```diff | |
| 126 | diff --git a/library/Cargo.toml b/library/Cargo.toml | |
| 127 | index e30e6240942..fb5a12f0065 100644 | |
| 128 | --- a/library/Cargo.toml | |
| 129 | +++ b/library/Cargo.toml | |
| 130 | @@ -59,3 +59,4 @@ rustflags = ["-Cpanic=abort"] | |
| 131 | rustc-std-workspace-core = { path = 'rustc-std-workspace-core' } | |
| 132 | rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' } | |
| 133 | rustc-std-workspace-std = { path = 'rustc-std-workspace-std' } | |
| 134 | +libc = { path = '<rust_root>/patches/libc' } | |
| 135 | diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml | |
| 136 | index e1725db60cf..46763cdf9a4 100644 | |
| 137 | --- a/src/bootstrap/Cargo.toml | |
| 138 | +++ b/src/bootstrap/Cargo.toml | |
| 139 | @@ -94,3 +94,6 @@ debug = 0 | |
| 140 | [profile.dev.package] | |
| 141 | # Only use debuginfo=1 to further reduce compile times. | |
| 142 | bootstrap.debug = 1 | |
| 143 | + | |
| 144 | +[patch.crates-io] | |
| 145 | +cc = { path = '<rust_root>/patches/cc-rs' } | |
| 146 | ``` | |
| 147 | ||
| 148 | </details> | |
| 149 | ||
| 150 | In contrast to `cc-rs` and `libc`, which are external crates resolved from | |
| 151 | [crates.io](https://crates.io/) and can be overridden using `[patch.crates-io]`, | |
| 152 | `backtrace` is included in the Rust repository as a git submodule under | |
| 153 | `<rust_root>/library/backtrace`. At the time of writing, the necessary change | |
| 154 | has not yet been committed there, which means an in-tree patch is currently | |
| 155 | required. The patch: | |
| 156 | ||
| 157 | <details> | |
| 158 | ||
| 159 | ```diff | |
| 160 | diff --git a/src/backtrace/libunwind.rs b/src/backtrace/libunwind.rs | |
| 161 | index 0564f2e..a8a0d1a 100644 | |
| 162 | --- a/src/backtrace/libunwind.rs | |
| 163 | +++ b/src/backtrace/libunwind.rs | |
| 164 | @@ -79,6 +79,18 @@ impl Frame { | |
| 165 | // clause, and if this is fixed that test in theory can be run on macOS! | |
| 166 | if cfg!(target_vendor = "apple") { | |
| 167 | self.ip() | |
| 168 | + } else if cfg!(target_abi = "pauthtest") { | |
| 169 | + // NOTE: ip here is an unsigned (raw) pointer, so we must not use | |
| 170 | + // uw::_Unwind_FindEnclosingFunction. | |
| 171 | + // | |
| 172 | + // Otherwise, in the pointer-authentication-enabled reference | |
| 173 | + // toolchain, libunwind would attempt to authenticate and re-sign | |
| 174 | + // values. Performing signing here is not safe: it could create a | |
| 175 | + // signing oracle, and more importantly it is incorrect under the | |
| 176 | + // expected signing schema. | |
| 177 | + // The schema requires the stack pointer (SP) as the discriminator. | |
| 178 | + // However, the SP available at this point would not match the SP | |
| 179 | + // at authentication/re-sign time, since | |
| 180 | + // _Unwind_FindEnclosingFunction constructs a new unwind context. | |
| 181 | + // The SP used here would therefore correspond to a different frame. | |
| 182 | + // As a result, we must return the raw value. | |
| 183 | + self.ip() | |
| 184 | } else { | |
| 185 | unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) } | |
| 186 | } | |
| 187 | ``` | |
| 188 | ||
| 189 | </details> | |
| 190 | ||
| 191 | The target can be built by enabling it for a `rustc` build. | |
| 192 | ||
| 193 | ```toml | |
| 194 | [build] | |
| 195 | target = ["aarch64-unknown-linux-pauthtest"] | |
| 196 | ``` | |
| 197 | ||
| 198 | Specify the binaries used by the target. | |
| 199 | ||
| 200 | ```toml | |
| 201 | [target.aarch64-unknown-linux-pauthtest] | |
| 202 | cc = "<path_to>/aarch64-unknown-linux-pauthtest-clang" | |
| 203 | ar = "<path_to>/llvm-ar" | |
| 204 | ranlib = "<path_to>/llvm-ranlib" | |
| 205 | linker = "<path_to>/aarch64-unknown-linux-pauthtest-clang" | |
| 206 | ``` | |
| 207 | ||
| 208 | Note that `cc` and `linker` must refer to the same binary (either Clang itself | |
| 209 | or its wrapper). The bootstrap process will fail if they differ. On non-AArch64 | |
| 210 | systems, ensure that QEMU is installed and that `binfmt_misc` is correctly | |
| 211 | configured so that foreign architecture binaries can be executed transparently. | |
| 212 | ||
| 213 | ## Building Rust programs | |
| 214 | ||
| 215 | Rust does not currently ship precompiled artifacts for this target. Programs | |
| 216 | must be built using a locally compiled Rust toolchain, with | |
| 217 | `aarch64-unknown-linux-pauthtest` target enabled. | |
| 218 | ||
| 219 | For a comprehensive example of how to interact between C and Rust programs | |
| 220 | within the testing framework please consult | |
| 221 | `<rust_root>/tests/run-make/pauth-quicksort-c-driver/rmake.rs`, the test builds | |
| 222 | a C executable linked against Rust library. | |
| 223 | `<rust_root>/tests/run-make/pauth-quicksort-rust-driver/rmake.rs` shows how to | |
| 224 | link a Rust program against a library compiled from a C source file. | |
| 225 | ||
| 226 | ### Minimal standalone Rust and C interoperability example | |
| 227 | ||
| 228 | A minimal standalone example demonstrating Rust and C interoperability on the | |
| 229 | `aarch64-unknown-linux-pauthtest` target is listed below. | |
| 230 | ||
| 231 | <details> | |
| 232 | ||
| 233 | * Project structure | |
| 234 | ||
| 235 | ```text | |
| 236 | rust_c_indirect/ | |
| 237 | ┣━ Cargo.toml | |
| 238 | ┣━ build.rs | |
| 239 | ┣━ src/ | |
| 240 | ┃ ┗━ main.rs | |
| 241 | ┣━ c_src/ | |
| 242 | ┃ ┗━ plugin.c | |
| 243 | ┗━ target/ | |
| 244 | ``` | |
| 245 | ||
| 246 | * `Cargo.toml` | |
| 247 | ||
| 248 | ```toml | |
| 249 | [package] | |
| 250 | name = "rust_c_indirect" | |
| 251 | edition = "2024" | |
| 252 | build = "build.rs" | |
| 253 | ``` | |
| 254 | ||
| 255 | * `build.rs` | |
| 256 | ||
| 257 | ```rust, ignore (platform-specific) | |
| 258 | use std::env; | |
| 259 | use std::path::Path; | |
| 260 | use std::process::Command; | |
| 261 | ||
| 262 | fn main() { | |
| 263 | println!("cargo:rerun-if-changed=c_src/plugin.c"); | |
| 264 | ||
| 265 | let clang = "<path_to>/aarch64-unknown-linux-pauthtest-clang"; | |
| 266 | ||
| 267 | let out_dir = env::var("OUT_DIR").unwrap(); | |
| 268 | let lib_path = Path::new(&out_dir).join("libplugin.so"); | |
| 269 | let c_src = "c_src/plugin.c"; | |
| 270 | ||
| 271 | let status = Command::new(clang) | |
| 272 | .args(["-shared", "-fPIC", c_src]) | |
| 273 | .arg("-o") | |
| 274 | .arg(&lib_path) | |
| 275 | .status() | |
| 276 | .unwrap_or_else(|_| panic!("failed to build shared library")); | |
| 277 | assert!(status.success(), "failed to build shared library"); | |
| 278 | ||
| 279 | println!("cargo:rustc-link-arg=-Wl,--dynamic-linker=<toolchain_root>/aarch64-linux-pauthtest/usr/lib/libc.so"); | |
| 280 | println!("cargo:rustc-link-arg=-Wl,-rpath,<toolchain_root>/aarch64-linux-pauthtest/usr/lib"); | |
| 281 | println!("cargo:rustc-link-search=native={}", out_dir); | |
| 282 | println!("cargo:rustc-link-lib=dylib=plugin"); | |
| 283 | } | |
| 284 | ||
| 285 | ``` | |
| 286 | ||
| 287 | * `src/main.rs` | |
| 288 | ||
| 289 | ```rust, ignore (platform-specific) | |
| 290 | use std::ptr; | |
| 291 | use std::os::raw::c_int; | |
| 292 | ||
| 293 | unsafe extern "C" { | |
| 294 | fn add(a: c_int, b: c_int) -> c_int; | |
| 295 | } | |
| 296 | ||
| 297 | static OP: unsafe extern "C" fn(c_int, c_int) -> c_int = add; | |
| 298 | ||
| 299 | fn main() { | |
| 300 | let a = 10; | |
| 301 | let b = 32; | |
| 302 | ||
| 303 | let op = unsafe { ptr::read_volatile(&raw const OP) }; | |
| 304 | let result = unsafe { op(a, b) }; | |
| 305 | ||
| 306 | println!("Result: {}", result); | |
| 307 | } | |
| 308 | ``` | |
| 309 | ||
| 310 | * `c_src/plugin.c` | |
| 311 | ||
| 312 | ```c | |
| 313 | int add(int a, int b) { return a + b; } | |
| 314 | ``` | |
| 315 | ||
| 316 | </details> | |
| 317 | ||
| 318 | * compile: `cargo build --target aarch64-unknown-linux-pauthtest --release` | |
| 319 | * run: `./target/aarch64-unknown-linux-pauthtest/release/rust_c_indirect` | |
| 320 | ||
| 321 | Please make sure that `LD_LIBRARY_PATH` points to the directory containing | |
| 322 | `libplugin.so`. For example: | |
| 323 | `LD_LIBRARY_PATH=./target/aarch64-unknown-linux-pauthtest/release/build/rust_c_indirect-<hash>/out/`. | |
| 324 | ||
| 325 | To inspect pointer authentication behavior in IR, build with: | |
| 326 | `RUSTFLAGS="--emit=llvm-ir"`. This generates an LLVM IR file, e.g.: | |
| 327 | `target/aarch64-unknown-linux-pauthtest/release/deps/rust_c_indirect-*.ll`. | |
| 328 | Relevant excerpt: | |
| 329 | ||
| 330 | ```llvm | |
| 331 | @_RNvCscVIHJvJIt8C_15rust_c_indirect2OP = internal constant ptr ptrauth (ptr @add, i32 0), align 8 | |
| 332 | ||
| 333 | %0 = load volatile ptr, ptr @_RNvCscVIHJvJIt8C_15rust_c_indirect2OP, align 8, !nonnull !5, !noundef !5 | |
| 334 | %1 = tail call noundef i32 %0(i32 noundef 10, i32 noundef 32) #6 [ "ptrauth"(i32 0, i64 0) ] | |
| 335 | ``` | |
| 336 | ||
| 337 | Which shows that: | |
| 338 | * function pointer (`@add`) is signed using `ptrauth`, when global variable is | |
| 339 | initialized, | |
| 340 | * the call is performed indirectly via a signed pointer, | |
| 341 | * the `ptrauth` operand bundle enforces authentication at call time. | |
| 342 | ||
| 343 | Note, when building crates it is necessary to explicitly point Cargo to the | |
| 344 | linker it has to use. This can be achieved by using a `config.toml` file (either | |
| 345 | local to the project, or global), or by setting a | |
| 346 | `CARGO_TARGET_AARCH64_UNKNOWN_LINUX_PAUTHTEST_LINKER` variable. For example: | |
| 347 | * `.cargo/config.toml` | |
| 348 | ||
| 349 | ```toml | |
| 350 | [target.aarch64-unknown-linux-pauthtest] | |
| 351 | linker = "<path_to>/aarch64-unknown-linux-pauthtest-clang" | |
| 352 | ``` | |
| 353 | ||
| 354 | * `export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_PAUTHTEST_LINKER=<path_to>/aarch64-unknown-linux-pauthtest-clang` | |
| 355 | ||
| 356 | Without it Cargo falls back to the system C toolchain (cc) and the compilation | |
| 357 | fails. | |
| 358 | ||
| 359 | ## Cross-compilation toolchains and C code | |
| 360 | ||
| 361 | This target supports interoperability with C code. A | |
| 362 | pointer-authentication-enabled sysroot, built as described in the toolchain | |
| 363 | build section of this document, is required. C code must be compiled with a | |
| 364 | compiler configuration that supports pointer authentication. Mixed Rust/C | |
| 365 | programs are supported and tested (e.g. quicksort examples). Pointer | |
| 366 | authentication semantics must be consistent across Rust and C components. Only | |
| 367 | dynamic linking is supported. | |
| 368 | ||
| 369 | The target can be cross-compiled from any Linux-based host, but execution | |
| 370 | requires an AArch64 system that implements Pointer Authentication (PAC). In | |
| 371 | practice, this means a CPU conforming to at least the Armv8.3-A architecture, | |
| 372 | where the | |
| 373 | [FEAT_PAuth](https://developer.arm.com/documentation/109697/2025_06/Feature-descriptions/The-Armv8-3-architecture-extension?lang=en#md448-the-armv83-architecture-extension__feat_FEAT_PAuth) | |
| 374 | extension is defined. | |
| 375 | ||
| 376 | Cross-compilation has been successfully performed on both | |
| 377 | `aarch64-unknown-linux-gnu` and `x86_64-unknown-linux-gnu` hosts. | |
| 378 | ||
| 379 | ## Testing | |
| 380 | ||
| 381 | This target can be tested as normal with `x.py`. | |
| 382 | The following categories are supported (all present in tree): | |
| 383 | * Assembly tests | |
| 384 | * pauth-basic.rs | |
| 385 | * LLVM IR/codegen tests | |
| 386 | * pauth-extern-c.rs | |
| 387 | * pauth-extern-c-direct-indirect-call.rs | |
| 388 | * pauth-extern-weak-global.rs | |
| 389 | * pauth-init-fini.rs | |
| 390 | * pauth-attr-special-funcs.rs | |
| 391 | * End-to-end execution tests | |
| 392 | * Rust-driven quicksort (pauth-quicksort-rust-driver) | |
| 393 | * C-driven quicksort (pauth-quicksort-c-driver) | |
| 394 | * UI error/warning reporting (the target does not support static linking) | |
| 395 | * crt-static-pauthtest.rs | |
| 396 | * pauth-static-link-warning | |
| 397 | ||
| 398 | All tests from `assembly-llvm`, `codegen-llvm`, `codegen-units`, `coverage`, | |
| 399 | `crashes`, `incremental`, `library`, `mir-opt`, `run-make`, `ui` and | |
| 400 | `ui-fulldeps` subsets are expected to pass. | |
| 401 | ||
| 402 | Command to run all passing tests (with tests added by this target explicitly | |
| 403 | named for convenience): | |
| 404 | ||
| 405 | ```sh | |
| 406 | x.py test --target aarch64-unknown-linux-pauthtest --force-rerun assembly-llvm \ | |
| 407 | codegen-llvm codegen-units coverage crashes incremental library mir-opt \ | |
| 408 | run-make ui ui-fulldeps \ | |
| 409 | tests/assembly-llvm/pauth-basic.rs \ | |
| 410 | tests/codegen-llvm/pauth/pauth-attr-special-funcs.rs \ | |
| 411 | tests/codegen-llvm/pauth/pauth-extern-c.rs \ | |
| 412 | tests/codegen-llvm/pauth/pauth-extern-c-direct-indirect-call.rs \ | |
| 413 | tests/codegen-llvm/pauth/pauth-extern-weak-global.rs \ | |
| 414 | tests/codegen-llvm/pauth/pauth-init-fini.rs \ | |
| 415 | tests/run-make/pauth-quicksort-rust-driver \ | |
| 416 | tests/run-make/pauth-quicksort-c-driver \ | |
| 417 | tests/run-make/pauth-static-link-warning \ | |
| 418 | tests/ui/statics/crt-static-pauthtest.rs | |
| 419 | ``` | |
| 420 | ||
| 421 | ## Limitations | |
| 422 | ||
| 423 | Operand bundles should only be attached to indirect function calls. However, | |
| 424 | function pointer signing is currently performed in `get_fn_addr`, which causes | |
| 425 | the logic to be applied too broadly, including to function values (not just | |
| 426 | pointers). As a result, direct calls using signed function values must also | |
| 427 | receive operand bundles. Once this is resolved, we should analyze each call and | |
| 428 | skip direct calls. | |
| 429 | For more information please see the discussion in the [rust-lang issue | |
| 430 | tracker](https://github.com/rust-lang/rust/issues/152532). | |
| 431 | ||
| 432 | The current version only supports C interoperability with pointer authentication | |
| 433 | features explicitly mentioned at the beginning of this document. Further work is | |
| 434 | needed to support configurable signing schemas (i.e. selection of signing keys, | |
| 435 | discriminators, address diversity, and features opt-in/opt-out) as defined by | |
| 436 | the LLVM pointer authentication model. | |
| 437 | ||
| 438 | C++ interoperability is not currently supported. Features such as signing C++ | |
| 439 | member function pointers, virtual function pointers, and virtual table pointers | |
| 440 | are not expected to work. |
src/doc/unstable-book/src/compiler-flags/min-recursion-limit.md created+12| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | # `min-recursion-limit` | |
| 2 | ||
| 3 | This flag sets a minimum recursion limit for the compiler. The final recursion limit is calculated as `max(min_recursion_limit, recursion_limit_from_crate)`. This cannot ever lower the recursion limit. Unless the current crate has an explicitly low `recursion_limit` attribute, any value less than the current default does not have an effect. | |
| 4 | ||
| 5 | The recursion limit affects (among other things): | |
| 6 | ||
| 7 | - macro expansion | |
| 8 | - the trait solver | |
| 9 | - const evaluation | |
| 10 | - query depth | |
| 11 | ||
| 12 | This flag is particularly useful when using the next trait solver (`-Z next-solver`), which may require a higher recursion limit for crates that were compiled successfully with the old solver. |
src/doc/unstable-book/src/compiler-flags/min-recursive-limit.md deleted-12| ... | ... | @@ -1,12 +0,0 @@ |
| 1 | # `min-recursion-limit` | |
| 2 | ||
| 3 | This flag sets a minimum recursion limit for the compiler. The final recursion limit is calculated as `max(min_recursion_limit, recursion_limit_from_crate)`. This cannot ever lower the recursion limit. Unless the current crate has an explicitly low `recursion_limit` attribute, any value less than the current default does not have an effect. | |
| 4 | ||
| 5 | The recursion limit affects (among other things): | |
| 6 | ||
| 7 | - macro expansion | |
| 8 | - the trait solver | |
| 9 | - const evaluation | |
| 10 | - query depth | |
| 11 | ||
| 12 | This flag is particularly useful when using the next trait solver (`-Z next-solver`), which may require a higher recursion limit for crates that were compiled successfully with the old solver. |
src/librustdoc/json/conversions.rs+59-10| ... | ... | @@ -270,6 +270,18 @@ impl FromClean<hir::ConstStability> for Stability { |
| 270 | 270 | } |
| 271 | 271 | } |
| 272 | 272 | |
| 273 | impl FromClean<hir::DefaultBodyStability> for Box<ProvidedDefaultUnstable> { | |
| 274 | fn from_clean(stab: &hir::DefaultBodyStability, _renderer: &JsonRenderer<'_>) -> Self { | |
| 275 | let hir::StabilityLevel::Unstable { .. } = stab.level else { | |
| 276 | bug!( | |
| 277 | "unexpected stable default-body stability, \ | |
| 278 | there's no stable equivalent of `#[rustc_default_body_unstable]`" | |
| 279 | ) | |
| 280 | }; | |
| 281 | Box::new(ProvidedDefaultUnstable { feature: stab.feature.to_string() }) | |
| 282 | } | |
| 283 | } | |
| 284 | ||
| 273 | 285 | impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> { |
| 274 | 286 | fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { |
| 275 | 287 | use clean::GenericArgs::*; |
| ... | ... | @@ -353,18 +365,23 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum |
| 353 | 365 | EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)), |
| 354 | 366 | VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)), |
| 355 | 367 | FunctionItem(f) => { |
| 356 | ItemEnum::Function(from_clean_function(f, true, header.unwrap(), renderer)) | |
| 368 | ItemEnum::Function(from_clean_function(f, true, None, header.unwrap(), renderer)) | |
| 357 | 369 | } |
| 358 | 370 | ForeignFunctionItem(f, _) => { |
| 359 | ItemEnum::Function(from_clean_function(f, false, header.unwrap(), renderer)) | |
| 371 | ItemEnum::Function(from_clean_function(f, false, None, header.unwrap(), renderer)) | |
| 360 | 372 | } |
| 361 | 373 | TraitItem(t) => ItemEnum::Trait(t.into_json(renderer)), |
| 362 | 374 | TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)), |
| 363 | MethodItem(m, _) => { | |
| 364 | ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer)) | |
| 365 | } | |
| 375 | MethodItem(m, _) => ItemEnum::Function(from_clean_function( | |
| 376 | m, | |
| 377 | true, | |
| 378 | default_body_stability_for_def_id(renderer.tcx, item.item_id.expect_def_id()) | |
| 379 | .map(|stab| stab.into_json(renderer)), | |
| 380 | header.unwrap(), | |
| 381 | renderer, | |
| 382 | )), | |
| 366 | 383 | RequiredMethodItem(m, _) => { |
| 367 | ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer)) | |
| 384 | ItemEnum::Function(from_clean_function(m, false, None, header.unwrap(), renderer)) | |
| 368 | 385 | } |
| 369 | 386 | ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)), |
| 370 | 387 | StaticItem(s) => ItemEnum::Static(from_clean_static(s, rustc_hir::Safety::Safe, renderer)), |
| ... | ... | @@ -385,23 +402,41 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum |
| 385 | 402 | }) |
| 386 | 403 | } |
| 387 | 404 | // FIXME(generic_const_items): Add support for generic associated consts. |
| 388 | RequiredAssocConstItem(_generics, ty) => { | |
| 389 | ItemEnum::AssocConst { type_: ty.into_json(renderer), value: None } | |
| 390 | } | |
| 405 | RequiredAssocConstItem(_generics, ty) => ItemEnum::AssocConst { | |
| 406 | type_: ty.into_json(renderer), | |
| 407 | value: None, | |
| 408 | default_unstable: None, | |
| 409 | }, | |
| 391 | 410 | // FIXME(generic_const_items): Add support for generic associated consts. |
| 392 | ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst { | |
| 411 | ProvidedAssocConstItem(ci) => ItemEnum::AssocConst { | |
| 393 | 412 | type_: ci.type_.into_json(renderer), |
| 394 | 413 | value: Some(ci.kind.expr(renderer.tcx)), |
| 414 | default_unstable: default_body_stability_for_def_id( | |
| 415 | renderer.tcx, | |
| 416 | item.item_id.expect_def_id(), | |
| 417 | ) | |
| 418 | .map(|stab| stab.into_json(renderer)), | |
| 419 | }, | |
| 420 | ImplAssocConstItem(ci) => ItemEnum::AssocConst { | |
| 421 | type_: ci.type_.into_json(renderer), | |
| 422 | value: Some(ci.kind.expr(renderer.tcx)), | |
| 423 | default_unstable: None, | |
| 395 | 424 | }, |
| 396 | 425 | RequiredAssocTypeItem(g, b) => ItemEnum::AssocType { |
| 397 | 426 | generics: g.into_json(renderer), |
| 398 | 427 | bounds: b.into_json(renderer), |
| 399 | 428 | type_: None, |
| 429 | default_unstable: None, | |
| 400 | 430 | }, |
| 401 | 431 | AssocTypeItem(t, b) => ItemEnum::AssocType { |
| 402 | 432 | generics: t.generics.into_json(renderer), |
| 403 | 433 | bounds: b.into_json(renderer), |
| 404 | 434 | type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)), |
| 435 | default_unstable: default_body_stability_for_def_id( | |
| 436 | renderer.tcx, | |
| 437 | item.item_id.expect_def_id(), | |
| 438 | ) | |
| 439 | .map(|stab| stab.into_json(renderer)), | |
| 405 | 440 | }, |
| 406 | 441 | // `convert_item` early returns `None` for stripped items, keywords, attributes and |
| 407 | 442 | // "special" macro rules. |
| ... | ... | @@ -815,6 +850,7 @@ impl FromClean<clean::Impl> for Impl { |
| 815 | 850 | pub(crate) fn from_clean_function( |
| 816 | 851 | clean::Function { decl, generics }: &clean::Function, |
| 817 | 852 | has_body: bool, |
| 853 | default_unstable: Option<Box<ProvidedDefaultUnstable>>, | |
| 818 | 854 | header: rustc_hir::FnHeader, |
| 819 | 855 | renderer: &JsonRenderer<'_>, |
| 820 | 856 | ) -> Function { |
| ... | ... | @@ -823,6 +859,7 @@ pub(crate) fn from_clean_function( |
| 823 | 859 | generics: generics.into_json(renderer), |
| 824 | 860 | header: header.into_json(renderer), |
| 825 | 861 | has_body, |
| 862 | default_unstable, | |
| 826 | 863 | } |
| 827 | 864 | } |
| 828 | 865 | |
| ... | ... | @@ -972,6 +1009,17 @@ impl FromClean<ItemType> for ItemKind { |
| 972 | 1009 | } |
| 973 | 1010 | } |
| 974 | 1011 | |
| 1012 | fn default_body_stability_for_def_id( | |
| 1013 | tcx: TyCtxt<'_>, | |
| 1014 | def_id: DefId, | |
| 1015 | ) -> Option<hir::DefaultBodyStability> { | |
| 1016 | let stability = tcx.lookup_default_body_stability(def_id)?; | |
| 1017 | match stability.level { | |
| 1018 | hir::StabilityLevel::Unstable { .. } => Some(stability), | |
| 1019 | hir::StabilityLevel::Stable { .. } => None, | |
| 1020 | } | |
| 1021 | } | |
| 1022 | ||
| 975 | 1023 | fn const_stability_for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::ConstStability> { |
| 976 | 1024 | if !tcx.is_conditionally_const(def_id) { |
| 977 | 1025 | // The item cannot be conditionally-const. No const stability here. |
| ... | ... | @@ -1040,6 +1088,7 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>) |
| 1040 | 1088 | AK::Deprecated { .. } => return Vec::new(), // Handled separately into Item::deprecation. |
| 1041 | 1089 | AK::Stability { .. } => return Vec::new(), // Handled separately into Item::stability |
| 1042 | 1090 | AK::RustcConstStability { .. } => return Vec::new(), // Handled separately into Item::const_stability. |
| 1091 | AK::RustcBodyStability { .. } => return Vec::new(), // Handled separately by `default_unstable`. | |
| 1043 | 1092 | |
| 1044 | 1093 | AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), |
| 1045 | 1094 |
src/rustdoc-json-types/lib.rs+37-2| ... | ... | @@ -114,8 +114,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc |
| 114 | 114 | // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line |
| 115 | 115 | // are deliberately not in a doc comment, because they need not be in public docs.) |
| 116 | 116 | // |
| 117 | // Latest feature: Add `Item::const_stability`. | |
| 118 | pub const FORMAT_VERSION: u32 = 59; | |
| 117 | // Latest feature: Add default-body stability metadata. | |
| 118 | pub const FORMAT_VERSION: u32 = 60; | |
| 119 | 119 | |
| 120 | 120 | /// The root of the emitted JSON blob. |
| 121 | 121 | /// |
| ... | ... | @@ -288,6 +288,9 @@ pub struct Item { |
| 288 | 288 | /// - `#[stable]` and `#[unstable]` attributes: see the [`Self::stability`] field instead. |
| 289 | 289 | /// - `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes: |
| 290 | 290 | /// see the [`Self::const_stability`] field instead. |
| 291 | /// - `#[rustc_default_body_unstable]` attributes: instead see `default_unstable` fields on | |
| 292 | /// item kinds that can have unstable default values, such as [`Function::default_unstable`], | |
| 293 | /// [`ItemEnum::AssocConst::default_unstable`], and [`ItemEnum::AssocType::default_unstable`]. | |
| 291 | 294 | /// |
| 292 | 295 | /// Attributes appear in pretty-printed Rust form, regardless of their formatting |
| 293 | 296 | /// in the original source code. For example: |
| ... | ... | @@ -367,6 +370,19 @@ pub enum StabilityLevel { |
| 367 | 370 | Unstable, |
| 368 | 371 | } |
| 369 | 372 | |
| 373 | /// Information about an unstable default provided by a trait item. | |
| 374 | /// | |
| 375 | /// Example unstable defaults include: | |
| 376 | /// - a stable trait function or method whose body is not stable | |
| 377 | /// - a stable trait associated type or const whose default value is not stable | |
| 378 | #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] | |
| 379 | #[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] | |
| 380 | #[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] | |
| 381 | pub struct ProvidedDefaultUnstable { | |
| 382 | /// The feature that must be enabled to use the provided default. | |
| 383 | pub feature: String, | |
| 384 | } | |
| 385 | ||
| 370 | 386 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] |
| 371 | 387 | #[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] |
| 372 | 388 | #[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] |
| ... | ... | @@ -379,6 +395,9 @@ pub enum StabilityLevel { |
| 379 | 395 | /// - `#[stable]` and `#[unstable]`. These are in [`Item::stability`] instead. |
| 380 | 396 | /// - `#[rustc_const_stable]` and `#[rustc_const_unstable]`. These are in |
| 381 | 397 | /// [`Item::const_stability`] instead. |
| 398 | /// - `#[rustc_default_body_unstable]`. These are in the `default_unstable` field on the appropriate | |
| 399 | /// item kinds: [`Function::default_unstable`], [`ItemEnum::AssocConst::default_unstable`], | |
| 400 | /// and [`ItemEnum::AssocType::default_unstable`]. | |
| 382 | 401 | pub enum Attribute { |
| 383 | 402 | /// `#[non_exhaustive]` |
| 384 | 403 | NonExhaustive, |
| ... | ... | @@ -875,6 +894,11 @@ pub enum ItemEnum { |
| 875 | 894 | /// // ^^^^^^^^^^ |
| 876 | 895 | /// ``` |
| 877 | 896 | value: Option<String>, |
| 897 | /// Metadata about an unstable default value provided for the associated constant, if any. | |
| 898 | /// | |
| 899 | /// Empty if the associated constant has no default (see [`ItemEnum::AssocConst::value`]), | |
| 900 | /// or if the default value is stable. | |
| 901 | default_unstable: Option<Box<ProvidedDefaultUnstable>>, | |
| 878 | 902 | }, |
| 879 | 903 | /// An associated type of a trait or a type. |
| 880 | 904 | AssocType { |
| ... | ... | @@ -899,6 +923,11 @@ pub enum ItemEnum { |
| 899 | 923 | /// ``` |
| 900 | 924 | #[serde(rename = "type")] |
| 901 | 925 | type_: Option<Type>, |
| 926 | /// Metadata about an unstable default value provided for the associated type, if any. | |
| 927 | /// | |
| 928 | /// Empty if the associated type has no default (see [`ItemEnum::AssocType::type_`]), | |
| 929 | /// or if the default value is stable. | |
| 930 | default_unstable: Option<Box<ProvidedDefaultUnstable>>, | |
| 902 | 931 | }, |
| 903 | 932 | } |
| 904 | 933 | |
| ... | ... | @@ -1188,6 +1217,12 @@ pub struct Function { |
| 1188 | 1217 | pub header: FunctionHeader, |
| 1189 | 1218 | /// Whether the function has a body, i.e. an implementation. |
| 1190 | 1219 | pub has_body: bool, |
| 1220 | /// Metadata about a possible unstable provided default implementation for trait methods. | |
| 1221 | /// | |
| 1222 | /// Only populated for function items inside traits. Empty if the trait method | |
| 1223 | /// does not have a default implementation (see [`Function::has_body`]), | |
| 1224 | /// or if its default implementation is stable. | |
| 1225 | pub default_unstable: Option<Box<ProvidedDefaultUnstable>>, | |
| 1191 | 1226 | } |
| 1192 | 1227 | |
| 1193 | 1228 | /// Generic parameters accepted by an item and `where` clauses imposed on it and the parameters. |
src/tools/compiletest/src/directives/directive_names.rs+2| ... | ... | @@ -106,6 +106,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ |
| 106 | 106 | "ignore-nvptx64-nvidia-cuda", |
| 107 | 107 | "ignore-openbsd", |
| 108 | 108 | "ignore-parallel-frontend", |
| 109 | "ignore-pauthtest", | |
| 109 | 110 | "ignore-powerpc", |
| 110 | 111 | "ignore-powerpc64", |
| 111 | 112 | "ignore-remote", |
| ... | ... | @@ -247,6 +248,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ |
| 247 | 248 | "only-musl", |
| 248 | 249 | "only-nightly", |
| 249 | 250 | "only-nvptx64", |
| 251 | "only-pauthtest", | |
| 250 | 252 | "only-powerpc", |
| 251 | 253 | "only-riscv32", |
| 252 | 254 | "only-riscv64", |
src/tools/jsondoclint/src/validator.rs+39-4| ... | ... | @@ -97,7 +97,7 @@ impl<'a> Validator<'a> { |
| 97 | 97 | ItemEnum::StructField(x) => self.check_struct_field(x), |
| 98 | 98 | ItemEnum::Enum(x) => self.check_enum(x), |
| 99 | 99 | ItemEnum::Variant(x) => self.check_variant(x, id), |
| 100 | ItemEnum::Function(x) => self.check_function(x), | |
| 100 | ItemEnum::Function(x) => self.check_function(x, id), | |
| 101 | 101 | ItemEnum::Trait(x) => self.check_trait(x, id), |
| 102 | 102 | ItemEnum::TraitAlias(x) => self.check_trait_alias(x), |
| 103 | 103 | ItemEnum::Impl(x) => self.check_impl(x, id), |
| ... | ... | @@ -114,12 +114,35 @@ impl<'a> Validator<'a> { |
| 114 | 114 | ItemEnum::Module(x) => self.check_module(x, id), |
| 115 | 115 | // FIXME: Why don't these have their own structs? |
| 116 | 116 | ItemEnum::ExternCrate { .. } => {} |
| 117 | ItemEnum::AssocConst { type_, value: _ } => self.check_type(type_), | |
| 118 | ItemEnum::AssocType { generics, bounds, type_ } => { | |
| 117 | ItemEnum::AssocConst { type_, value, default_unstable } => { | |
| 118 | self.check_type(type_); | |
| 119 | if value.is_none() | |
| 120 | && let Some(default_unstable) = default_unstable | |
| 121 | { | |
| 122 | self.fail( | |
| 123 | id, | |
| 124 | ErrorKind::Custom(format!( | |
| 125 | "`default_unstable` must be `None` when `value` is `None`, but \ | |
| 126 | assoc const id {} had `default_unstable` with feature `{}`", | |
| 127 | id.0, default_unstable.feature | |
| 128 | )), | |
| 129 | ); | |
| 130 | } | |
| 131 | } | |
| 132 | ItemEnum::AssocType { generics, bounds, type_, default_unstable } => { | |
| 119 | 133 | self.check_generics(generics); |
| 120 | 134 | bounds.iter().for_each(|b| self.check_generic_bound(b)); |
| 121 | 135 | if let Some(ty) = type_ { |
| 122 | 136 | self.check_type(ty); |
| 137 | } else if let Some(default_unstable) = default_unstable { | |
| 138 | self.fail( | |
| 139 | id, | |
| 140 | ErrorKind::Custom(format!( | |
| 141 | "`default_unstable` must be `None` when `type_` is `None`, but \ | |
| 142 | assoc type id {} had `default_unstable` with feature `{}`", | |
| 143 | id.0, default_unstable.feature | |
| 144 | )), | |
| 145 | ); | |
| 123 | 146 | } |
| 124 | 147 | } |
| 125 | 148 | } |
| ... | ... | @@ -194,9 +217,21 @@ impl<'a> Validator<'a> { |
| 194 | 217 | } |
| 195 | 218 | } |
| 196 | 219 | |
| 197 | fn check_function(&mut self, x: &'a Function) { | |
| 220 | fn check_function(&mut self, x: &'a Function, id: &Id) { | |
| 198 | 221 | self.check_generics(&x.generics); |
| 199 | 222 | self.check_function_signature(&x.sig); |
| 223 | if !x.has_body | |
| 224 | && let Some(default_unstable) = &x.default_unstable | |
| 225 | { | |
| 226 | self.fail( | |
| 227 | id, | |
| 228 | ErrorKind::Custom(format!( | |
| 229 | "`default_unstable` must be `None` when `has_body == false`, but \ | |
| 230 | function item id {} had `default_unstable` with feature `{}`", | |
| 231 | id.0, default_unstable.feature | |
| 232 | )), | |
| 233 | ); | |
| 234 | } | |
| 200 | 235 | } |
| 201 | 236 | |
| 202 | 237 | fn check_trait(&mut self, x: &'a Trait, id: &Id) { |
src/tools/jsondoclint/src/validator/tests.rs+153-1| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | use rustc_hash::FxHashMap; |
| 2 | use rustdoc_json_types::{Abi, FORMAT_VERSION, FunctionHeader, Item, ItemKind, Visibility}; | |
| 2 | use rustdoc_json_types::{ | |
| 3 | Abi, FORMAT_VERSION, FunctionHeader, Item, ItemKind, ProvidedDefaultUnstable, Visibility, | |
| 4 | }; | |
| 3 | 5 | |
| 4 | 6 | use super::*; |
| 5 | 7 | use crate::json_find::SelectorPart; |
| ... | ... | @@ -221,6 +223,7 @@ fn errors_on_missing_path() { |
| 221 | 223 | abi: Abi::Rust, |
| 222 | 224 | }, |
| 223 | 225 | has_body: true, |
| 226 | default_unstable: None, | |
| 224 | 227 | }), |
| 225 | 228 | }, |
| 226 | 229 | ), |
| ... | ... | @@ -246,6 +249,155 @@ fn errors_on_missing_path() { |
| 246 | 249 | ); |
| 247 | 250 | } |
| 248 | 251 | |
| 252 | fn krate_with_trait_item(inner: ItemEnum) -> Crate { | |
| 253 | let item_id = Id(2); | |
| 254 | Crate { | |
| 255 | root: Id(0), | |
| 256 | crate_version: None, | |
| 257 | includes_private: false, | |
| 258 | index: FxHashMap::from_iter([ | |
| 259 | ( | |
| 260 | Id(0), | |
| 261 | Item { | |
| 262 | id: Id(0), | |
| 263 | crate_id: 0, | |
| 264 | name: Some("root".to_owned()), | |
| 265 | span: None, | |
| 266 | visibility: Visibility::Public, | |
| 267 | docs: None, | |
| 268 | links: FxHashMap::default(), | |
| 269 | attrs: Vec::new(), | |
| 270 | deprecation: None, | |
| 271 | stability: None, | |
| 272 | const_stability: None, | |
| 273 | inner: ItemEnum::Module(Module { | |
| 274 | is_crate: true, | |
| 275 | items: vec![Id(1)], | |
| 276 | is_stripped: false, | |
| 277 | }), | |
| 278 | }, | |
| 279 | ), | |
| 280 | ( | |
| 281 | Id(1), | |
| 282 | Item { | |
| 283 | id: Id(1), | |
| 284 | crate_id: 0, | |
| 285 | name: Some("Trait".to_owned()), | |
| 286 | span: None, | |
| 287 | visibility: Visibility::Public, | |
| 288 | docs: None, | |
| 289 | links: FxHashMap::default(), | |
| 290 | attrs: Vec::new(), | |
| 291 | deprecation: None, | |
| 292 | stability: None, | |
| 293 | const_stability: None, | |
| 294 | inner: ItemEnum::Trait(Trait { | |
| 295 | is_auto: false, | |
| 296 | is_unsafe: false, | |
| 297 | is_dyn_compatible: true, | |
| 298 | items: vec![item_id], | |
| 299 | generics: Generics { params: vec![], where_predicates: vec![] }, | |
| 300 | bounds: vec![], | |
| 301 | implementations: vec![], | |
| 302 | }), | |
| 303 | }, | |
| 304 | ), | |
| 305 | ( | |
| 306 | item_id, | |
| 307 | Item { | |
| 308 | id: item_id, | |
| 309 | crate_id: 0, | |
| 310 | name: Some("TraitItem".to_owned()), | |
| 311 | span: None, | |
| 312 | visibility: Visibility::Public, | |
| 313 | docs: None, | |
| 314 | links: FxHashMap::default(), | |
| 315 | attrs: Vec::new(), | |
| 316 | deprecation: None, | |
| 317 | stability: None, | |
| 318 | const_stability: None, | |
| 319 | inner, | |
| 320 | }, | |
| 321 | ), | |
| 322 | ]), | |
| 323 | paths: FxHashMap::default(), | |
| 324 | external_crates: FxHashMap::default(), | |
| 325 | target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] }, | |
| 326 | format_version: FORMAT_VERSION, | |
| 327 | } | |
| 328 | } | |
| 329 | ||
| 330 | #[test] | |
| 331 | fn errors_on_default_unstable_without_function_body() { | |
| 332 | let krate = krate_with_trait_item(ItemEnum::Function(Function { | |
| 333 | sig: FunctionSignature { inputs: vec![], output: None, is_c_variadic: false }, | |
| 334 | generics: Generics { params: vec![], where_predicates: vec![] }, | |
| 335 | header: FunctionHeader { | |
| 336 | is_const: false, | |
| 337 | is_unsafe: false, | |
| 338 | is_async: false, | |
| 339 | abi: Abi::Rust, | |
| 340 | }, | |
| 341 | has_body: false, | |
| 342 | default_unstable: Some(Box::new(ProvidedDefaultUnstable { feature: "feature".to_owned() })), | |
| 343 | })); | |
| 344 | ||
| 345 | check( | |
| 346 | &krate, | |
| 347 | &[Error { | |
| 348 | id: Id(2), | |
| 349 | kind: ErrorKind::Custom( | |
| 350 | "`default_unstable` must be `None` when `has_body == false`, but \ | |
| 351 | function item id 2 had `default_unstable` with feature `feature`" | |
| 352 | .to_owned(), | |
| 353 | ), | |
| 354 | }], | |
| 355 | ); | |
| 356 | } | |
| 357 | ||
| 358 | #[test] | |
| 359 | fn errors_on_default_unstable_without_assoc_const_value() { | |
| 360 | let krate = krate_with_trait_item(ItemEnum::AssocConst { | |
| 361 | type_: Type::Primitive("usize".to_owned()), | |
| 362 | value: None, | |
| 363 | default_unstable: Some(Box::new(ProvidedDefaultUnstable { feature: "feature".to_owned() })), | |
| 364 | }); | |
| 365 | ||
| 366 | check( | |
| 367 | &krate, | |
| 368 | &[Error { | |
| 369 | id: Id(2), | |
| 370 | kind: ErrorKind::Custom( | |
| 371 | "`default_unstable` must be `None` when `value` is `None`, but \ | |
| 372 | assoc const id 2 had `default_unstable` with feature `feature`" | |
| 373 | .to_owned(), | |
| 374 | ), | |
| 375 | }], | |
| 376 | ); | |
| 377 | } | |
| 378 | ||
| 379 | #[test] | |
| 380 | fn errors_on_default_unstable_without_assoc_type_default() { | |
| 381 | let krate = krate_with_trait_item(ItemEnum::AssocType { | |
| 382 | generics: Generics { params: vec![], where_predicates: vec![] }, | |
| 383 | bounds: vec![], | |
| 384 | type_: None, | |
| 385 | default_unstable: Some(Box::new(ProvidedDefaultUnstable { feature: "feature".to_owned() })), | |
| 386 | }); | |
| 387 | ||
| 388 | check( | |
| 389 | &krate, | |
| 390 | &[Error { | |
| 391 | id: Id(2), | |
| 392 | kind: ErrorKind::Custom( | |
| 393 | "`default_unstable` must be `None` when `type_` is `None`, but \ | |
| 394 | assoc type id 2 had `default_unstable` with feature `feature`" | |
| 395 | .to_owned(), | |
| 396 | ), | |
| 397 | }], | |
| 398 | ); | |
| 399 | } | |
| 400 | ||
| 249 | 401 | #[test] |
| 250 | 402 | #[should_panic = "LOCAL_CRATE_ID is wrong"] |
| 251 | 403 | fn checks_local_crate_id_is_correct() { |
src/tools/run-make-support/Cargo.toml+1-1| ... | ... | @@ -13,7 +13,7 @@ edition = "2024" |
| 13 | 13 | bstr = "1.12" |
| 14 | 14 | gimli = "0.32" |
| 15 | 15 | libc = "0.2" |
| 16 | object = "0.37" | |
| 16 | object = { version = "0.37", features = ["wasm"] } | |
| 17 | 17 | regex = "1.11" |
| 18 | 18 | serde_json = "1.0" |
| 19 | 19 | similar = "2.7" |
tests/assembly-llvm/asm/aarch64-outline-atomics.rs+3| ... | ... | @@ -2,6 +2,9 @@ |
| 2 | 2 | //@ compile-flags: -Copt-level=3 |
| 3 | 3 | //@ only-aarch64 |
| 4 | 4 | //@ only-linux |
| 5 | // aarch64-unknown-linux-pauthtest requires armv8.3-a, which includes Large System Extensions, | |
| 6 | // providing hardware implementations of atomic operations. | |
| 7 | //@ ignore-pauthtest | |
| 5 | 8 | |
| 6 | 9 | #![crate_type = "rlib"] |
| 7 | 10 |
tests/assembly-llvm/pauth-basic.rs created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | //@ add-minicore | |
| 2 | //@ assembly-output: emit-asm | |
| 3 | //@ only-pauthtest | |
| 4 | //@ revisions: aarch64_unknown_linux_pauthtest | |
| 5 | //@ [aarch64_unknown_linux_pauthtest] compile-flags: --target=aarch64-unknown-linux-pauthtest | |
| 6 | //@ [aarch64_unknown_linux_pauthtest] needs-llvm-components: aarch64 | |
| 7 | ||
| 8 | #![feature(no_core, lang_items)] | |
| 9 | #![no_std] | |
| 10 | #![no_core] | |
| 11 | #![crate_type = "lib"] | |
| 12 | ||
| 13 | extern crate minicore; | |
| 14 | ||
| 15 | #[no_mangle] | |
| 16 | #[inline(never)] | |
| 17 | pub extern "C" fn c_func(a: i32) -> i32 { | |
| 18 | a | |
| 19 | } | |
| 20 | ||
| 21 | #[no_mangle] | |
| 22 | #[inline(never)] | |
| 23 | fn call_through(f: extern "C" fn(i32) -> i32, x: i32) -> i32 { | |
| 24 | f(x) | |
| 25 | } | |
| 26 | ||
| 27 | #[no_mangle] | |
| 28 | #[inline(never)] | |
| 29 | pub fn call_c_func(x: i32) -> i32 { | |
| 30 | call_through(c_func, x) | |
| 31 | } | |
| 32 | ||
| 33 | // CHECK-LABEL: call_through: | |
| 34 | // CHECK: mov [[PTR:x[0-9]+]], x0 | |
| 35 | // CHECK: mov w0, w1 | |
| 36 | // CHECK: braaz [[PTR]] | |
| 37 | ||
| 38 | // CHECK-LABEL: call_c_func: | |
| 39 | // CHECK: adrp [[GOT_REG:x[0-9]+]], :got:c_func | |
| 40 | // CHECK: ldr [[GOT_REG]], [[[GOT_REG]], :got_lo12:c_func] | |
| 41 | // CHECK: paciza [[FN_REG:x[0-9]+]] | |
| 42 | // CHECK: mov w1, w0 | |
| 43 | // CHECK: mov x0, [[FN_REG]] | |
| 44 | // CHECK: b call_through |
tests/assembly-llvm/targets/targets-elf.rs+3| ... | ... | @@ -55,6 +55,9 @@ |
| 55 | 55 | //@ revisions: aarch64_unknown_linux_ohos |
| 56 | 56 | //@ [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos |
| 57 | 57 | //@ [aarch64_unknown_linux_ohos] needs-llvm-components: aarch64 |
| 58 | //@ revisions: aarch64_unknown_linux_pauthtest | |
| 59 | //@ [aarch64_unknown_linux_pauthtest] compile-flags: --target aarch64-unknown-linux-pauthtest | |
| 60 | //@ [aarch64_unknown_linux_pauthtest] needs-llvm-components: aarch64 | |
| 58 | 61 | //@ revisions: aarch64_unknown_managarm_mlibc |
| 59 | 62 | //@ [aarch64_unknown_managarm_mlibc] compile-flags: --target aarch64-unknown-managarm-mlibc |
| 60 | 63 | //@ [aarch64_unknown_managarm_mlibc] needs-llvm-components: aarch64 |
tests/auxiliary/minicore.rs+23| ... | ... | @@ -8,7 +8,10 @@ |
| 8 | 8 | //! items. For identical error output, any `diagnostic` attributes (e.g. `on_unimplemented`) |
| 9 | 9 | //! should also be replicated here. |
| 10 | 10 | //! - Be careful of adding new features and things that are only available for a subset of targets. |
| 11 | //! - `Sync` is only provided such that the minimal set of impls required by tests is met (not | |
| 12 | //! exhaustive covering of all possible function pointer signatures). | |
| 11 | 13 | //! |
| 14 | ||
| 12 | 15 | //! # References |
| 13 | 16 | //! |
| 14 | 17 | //! This is partially adapted from `rustc_codegen_cranelift`: |
| ... | ... | @@ -299,6 +302,16 @@ impl_marker_trait!( |
| 299 | 302 | impl Sync for () {} |
| 300 | 303 | |
| 301 | 304 | impl<T, const N: usize> Sync for [T; N] {} |
| 305 | // Function pointers are treated as `Sync` to match real `core` behavior. | |
| 306 | // | |
| 307 | // Minicore provides only the minimal set of impls required by tests. Rather | |
| 308 | // than exhaustively covering all possible function pointer signatures, | |
| 309 | // additional impls should be added as needed. | |
| 310 | impl<R> Sync for fn() -> R {} | |
| 311 | impl<R> Sync for extern "C" fn() -> R {} | |
| 312 | impl<R> Sync for unsafe extern "C" fn() -> R {} | |
| 313 | impl<A, R> Sync for extern "C" fn(A) -> R {} | |
| 314 | impl<A, R> Sync for unsafe extern "C" fn(A) -> R {} | |
| 302 | 315 | |
| 303 | 316 | #[lang = "drop_glue"] |
| 304 | 317 | fn drop_glue<T>(_: &mut T) {} |
| ... | ... | @@ -367,6 +380,16 @@ pub mod ptr { |
| 367 | 380 | } |
| 368 | 381 | } |
| 369 | 382 | |
| 383 | pub mod hint { | |
| 384 | #[inline] | |
| 385 | pub fn black_box<T>(dummy: T) -> T { | |
| 386 | #[rustc_intrinsic] | |
| 387 | fn black_box<T>(dummy: T) -> T; | |
| 388 | ||
| 389 | unsafe { black_box(dummy) } | |
| 390 | } | |
| 391 | } | |
| 392 | ||
| 370 | 393 | #[lang = "c_void"] |
| 371 | 394 | #[repr(u8)] |
| 372 | 395 | pub enum c_void { |
tests/codegen-llvm/box-uninit-bytes.rs+1-1| ... | ... | @@ -43,4 +43,4 @@ pub fn box_lotsa_padding() -> Box<LotsaPadding> { |
| 43 | 43 | // from the CHECK-NOT above, and also verify the attributes got set reasonably. |
| 44 | 44 | // CHECK: declare {{(dso_local )?}}noalias noundef ptr @{{.*}}__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef range(i{{[0-9]+}} 1, {{-2147483647|-9223372036854775807}})) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] |
| 45 | 45 | |
| 46 | // CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} } | |
| 46 | // CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned"){{.*}} allocsize(0) {{(uwtable )?}}{{.*}}"alloc-family"="__rust_alloc" {{.*}} } |
tests/codegen-llvm/cffi/c-variadic.rs+4| ... | ... | @@ -1,5 +1,9 @@ |
| 1 | 1 | //@ needs-unwind |
| 2 | 2 | //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 |
| 3 | // Pauthtest generates pointer authentication metadata for call instructions | |
| 4 | // and wraps function pointers in ConstPtrAuth. Disable this test for this target | |
| 5 | // to avoid clutter from pointer authentication complexity. | |
| 6 | //@ ignore-pauthtest | |
| 3 | 7 | |
| 4 | 8 | #![crate_type = "lib"] |
| 5 | 9 | #![feature(c_variadic)] |
tests/codegen-llvm/inline-always-works-always.rs+2| ... | ... | @@ -2,6 +2,8 @@ |
| 2 | 2 | //@[NO-OPT] compile-flags: -Copt-level=0 |
| 3 | 3 | //@[SIZE-OPT] compile-flags: -Copt-level=s |
| 4 | 4 | //@[SPEED-OPT] compile-flags: -Copt-level=3 |
| 5 | // Pointer authenticated calls are not guaranteed to be inlined. | |
| 6 | //@ ignore-pauthtest | |
| 5 | 7 | |
| 6 | 8 | #![crate_type = "rlib"] |
| 7 | 9 |
tests/codegen-llvm/issues/issue-73258.rs+5-3| ... | ... | @@ -3,6 +3,8 @@ |
| 3 | 3 | #![crate_type = "lib"] |
| 4 | 4 | |
| 5 | 5 | // Adapted from <https://github.com/rust-lang/rust/issues/73258#issue-637346014> |
| 6 | // We explicitly match against `call{{.*}}(` because the emitted call may carry attributes (e.g. | |
| 7 | // `ptrauth-calls`), which would otherwise make a plain `call` pattern too permissive. | |
| 6 | 8 | |
| 7 | 9 | #[derive(Clone, Copy)] |
| 8 | 10 | #[repr(u8)] |
| ... | ... | @@ -17,7 +19,7 @@ pub enum Foo { |
| 17 | 19 | #[no_mangle] |
| 18 | 20 | pub unsafe fn issue_73258(ptr: *const Foo) -> Foo { |
| 19 | 21 | // CHECK-NOT: icmp |
| 20 | // CHECK-NOT: call | |
| 22 | // CHECK-NOT: call{{.*}}( | |
| 21 | 23 | // CHECK-NOT: br {{.*}} |
| 22 | 24 | // CHECK-NOT: select |
| 23 | 25 | |
| ... | ... | @@ -25,14 +27,14 @@ pub unsafe fn issue_73258(ptr: *const Foo) -> Foo { |
| 25 | 27 | // CHECK-SAME: !range ! |
| 26 | 28 | |
| 27 | 29 | // CHECK-NOT: icmp |
| 28 | // CHECK-NOT: call | |
| 30 | // CHECK-NOT: call{{.*}}( | |
| 29 | 31 | // CHECK-NOT: br {{.*}} |
| 30 | 32 | // CHECK-NOT: select |
| 31 | 33 | |
| 32 | 34 | // CHECK: ret i8 %[[R]] |
| 33 | 35 | |
| 34 | 36 | // CHECK-NOT: icmp |
| 35 | // CHECK-NOT: call | |
| 37 | // CHECK-NOT: call{{.*}}( | |
| 36 | 38 | // CHECK-NOT: br {{.*}} |
| 37 | 39 | // CHECK-NOT: select |
| 38 | 40 | let k: Option<Foo> = Some(ptr.read()); |
tests/codegen-llvm/pauth/pauth-attr-special-funcs.rs created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | //@ only-pauthtest | |
| 2 | //@ compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 | |
| 3 | // Make sure that compiler generated functions (main wrapper and __rust_try) also have ptrauth | |
| 4 | // attributes set correctly. Rustc only generates __rust_try at O0, so use that opt level for the | |
| 5 | // test. | |
| 6 | ||
| 7 | //@ needs-llvm-components: aarch64 | |
| 8 | ||
| 9 | use std::panic; | |
| 10 | ||
| 11 | // CHECK: define {{.*}} @__rust_try{{.*}} [[ATTR_TRY:#[0-9]+]] | |
| 12 | // CHECK: define {{.*}} @main{{.*}} [[ATTR_MAIN:#[0-9]+]] | |
| 13 | ||
| 14 | // CHECK: attributes [[ATTR_TRY]] = { {{.*}}"aarch64-jump-table-hardening" | |
| 15 | // CHECK-DAG: "ptrauth-auth-traps" | |
| 16 | // CHECK-DAG: "ptrauth-calls" | |
| 17 | // CHECK-DAG: "ptrauth-indirect-gotos" | |
| 18 | // CHECK-DAG: "ptrauth-returns" | |
| 19 | ||
| 20 | // CHECK: attributes [[ATTR_MAIN]] = { {{.*}}"aarch64-jump-table-hardening" | |
| 21 | // CHECK-DAG: "ptrauth-auth-traps" | |
| 22 | // CHECK-DAG: "ptrauth-calls" | |
| 23 | // CHECK-DAG: "ptrauth-indirect-gotos" | |
| 24 | // CHECK-DAG: "ptrauth-returns" | |
| 25 | fn main() { | |
| 26 | let _ = panic::catch_unwind(|| { | |
| 27 | panic!("BOOM"); | |
| 28 | }); | |
| 29 | } | |
| 30 | ||
| 31 | // CHECK: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} |
tests/codegen-llvm/pauth/pauth-extern-c-direct-indirect-call.rs created+98| ... | ... | @@ -0,0 +1,98 @@ |
| 1 | //@ add-minicore | |
| 2 | // ignore-tidy-linelength | |
| 3 | //@ only-pauthtest | |
| 4 | //@ revisions: O0_PAUTH O3_PAUTH | |
| 5 | ||
| 6 | //@ [O0_PAUTH] needs-llvm-components: aarch64 | |
| 7 | //@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 | |
| 8 | //@ [O3_PAUTH] needs-llvm-components: aarch64 | |
| 9 | //@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 | |
| 10 | ||
| 11 | // Make sure that direct extern "C" calls are not handled by pointer authentication operand bundle | |
| 12 | // logic. | |
| 13 | #![feature(no_core, lang_items)] | |
| 14 | #![no_std] | |
| 15 | #![no_core] | |
| 16 | #![crate_type = "lib"] | |
| 17 | ||
| 18 | extern crate minicore; | |
| 19 | use minicore::hint::black_box; | |
| 20 | use minicore::*; | |
| 21 | ||
| 22 | extern "C" { | |
| 23 | fn rand() -> bool; | |
| 24 | fn add(a: i32, b: i32) -> i32; | |
| 25 | fn sub(a: i32, b: i32) -> i32; | |
| 26 | ||
| 27 | // Corresponds to: void *woof; | |
| 28 | static mut woof: *mut c_void; | |
| 29 | fn direct_function_taking_void_arg(data: *mut c_void); | |
| 30 | fn direct_no_arg(); | |
| 31 | fn direct_function_taking_fp_arg(func: unsafe extern "C" fn()); | |
| 32 | } | |
| 33 | ||
| 34 | type CFnPtr = unsafe extern "C" fn(i32, i32) -> i32; | |
| 35 | ||
| 36 | // CHECK-LABE: test_indirect_call | |
| 37 | #[inline(never)] | |
| 38 | fn test_indirect_call() { | |
| 39 | let fp_add: CFnPtr = black_box(add); | |
| 40 | let fp_sub: CFnPtr = black_box(sub); | |
| 41 | ||
| 42 | unsafe { | |
| 43 | let a = black_box(fp_add); | |
| 44 | let b = black_box(fp_sub); | |
| 45 | ||
| 46 | // O0_PAUTH: call i32 %{{.*}}(i32 7, i32 4) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 47 | // O3_PAUTH: call noundef i32 %{{.*}}(i32 noundef 7, i32 noundef 4) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 48 | let _id1 = a(7, 4); | |
| 49 | ||
| 50 | // O0_PAUTH: call i32 %{{.*}}(i32 10, i32 6) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 51 | // O3_PAUTH: call noundef i32 %{{.*}}(i32 noundef 10, i32 noundef 6) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 52 | let _id2 = b(10, 6); | |
| 53 | } | |
| 54 | ||
| 55 | // Also test calling via conditional pointer | |
| 56 | unsafe { | |
| 57 | // O0_PAUTH: call {{.*}}i1 ptrauth (ptr @rand, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 58 | // O3_PAUTH: call {{.*}}i1 @rand() # | |
| 59 | let use_add = rand(); | |
| 60 | // O0_PAUTH: store ptr ptrauth (ptr @sub, i32 0), ptr %[[FP_O0:[a-zA-Z0-9_.]+]] | |
| 61 | // O0_PAUTH: store ptr ptrauth (ptr @add, i32 0), ptr %[[FP_O0]]{{.*}} | |
| 62 | // O0_PAUTH: %[[LOAD_FP_O0:[a-zA-Z0-9_.]+]] = load ptr, ptr %[[FP_O0]]{{.*}} | |
| 63 | // O3_PAUTH: %[[FP_O3:.*]] = select i1 %{{.*}}, ptr ptrauth (ptr @add, i32 0), ptr ptrauth (ptr @sub, i32 0) | |
| 64 | let fp: CFnPtr = if use_add { add } else { sub }; | |
| 65 | // O0_PAUTH: call i32 %[[LOAD_FP_O0]](i32 1, i32 2) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 66 | // O3_PAUTH: call {{.*}}i32 %[[FP_O3]](i32 noundef 1, i32 noundef 2) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 67 | let _id3 = fp(1, 2); | |
| 68 | } | |
| 69 | ||
| 70 | unsafe { | |
| 71 | direct_function_taking_fp_arg(direct_no_arg); | |
| 72 | } | |
| 73 | } | |
| 74 | ||
| 75 | // CHECK-LABEL: test_direct_call | |
| 76 | #[inline(never)] | |
| 77 | fn test_direct_call() { | |
| 78 | unsafe { | |
| 79 | // O0_PAUTH: call {{.*}}i32 ptrauth (ptr @add, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 80 | // O3_PAUTH: call {{.*}}i32 @add(i32 {{.*}}2, i32 {{.*}}3) # | |
| 81 | let _d1 = add(2, 3); | |
| 82 | // O0_PAUTH: call {{.*}}i32 ptrauth (ptr @sub, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 83 | // O3_PAUTH: call {{.*}}i32 @sub(i32 {{.*}}5, i32 {{.*}}1) # | |
| 84 | let _d2 = sub(5, 1); | |
| 85 | ||
| 86 | // O0_PAUTH: call {{.*}}void ptrauth (ptr @direct_function_taking_void_arg, i32 0)({{.*}}) #{{[0-9]+}} [ "ptrauth"(i32 0, i64 0) ] | |
| 87 | // O3_PAUTH: {{(tail )?}}call void @direct_function_taking_void_arg(ptr noundef %{{.*}}) # | |
| 88 | direct_function_taking_void_arg(woof); | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 92 | pub fn entry() { | |
| 93 | test_indirect_call(); | |
| 94 | test_direct_call(); | |
| 95 | } | |
| 96 | ||
| 97 | // O0_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} | |
| 98 | // O3_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} |
tests/codegen-llvm/pauth/pauth-extern-c.rs created+75| ... | ... | @@ -0,0 +1,75 @@ |
| 1 | // ignore-tidy-linelength | |
| 2 | //@ only-pauthtest | |
| 3 | //@ add-minicore | |
| 4 | ||
| 5 | //@ revisions: O0_PAUTH O3_PAUTH O0_PAUTH-ELF-GOT O3_PAUTH-ELF-GOT O0_NO_PAUTH O3_NO_PAUTH | |
| 6 | ||
| 7 | //@ [O0_PAUTH] needs-llvm-components: aarch64 | |
| 8 | //@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 | |
| 9 | //@ [O3_PAUTH] needs-llvm-components: aarch64 | |
| 10 | //@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 | |
| 11 | //@ [O0_PAUTH-ELF-GOT] needs-llvm-components: aarch64 | |
| 12 | //@ [O0_PAUTH-ELF-GOT] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 -Z ptrauth-elf-got | |
| 13 | //@ [O3_PAUTH-ELF-GOT] needs-llvm-components: aarch64 | |
| 14 | //@ [O3_PAUTH-ELF-GOT] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 -Z ptrauth-elf-got | |
| 15 | //@ [O0_NO_PAUTH] needs-llvm-components: aarch64 | |
| 16 | //@ [O0_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=0 | |
| 17 | //@ [O3_NO_PAUTH] needs-llvm-components: aarch64 | |
| 18 | //@ [O3_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=3 | |
| 19 | ||
| 20 | #![crate_type = "lib"] | |
| 21 | #![no_std] | |
| 22 | #![no_core] | |
| 23 | #![feature(no_core)] | |
| 24 | ||
| 25 | extern crate minicore; | |
| 26 | ||
| 27 | type FnPtr = unsafe extern "C" fn(i32, i32) -> i32; | |
| 28 | // O0_NO_PAUTH-NOT: "ptrauth"(i32 | |
| 29 | // O3_NO_PAUTH-NOT: "ptrauth"(i32 | |
| 30 | ||
| 31 | // O0_PAUTH: define {{.*}}test_entry | |
| 32 | // O3_PAUTH: define {{.*}}test_entry | |
| 33 | #[no_mangle] | |
| 34 | pub unsafe extern "C" fn test_entry(x: usize) { | |
| 35 | // O0_PAUTH: call{{.*}}_RNvCshUtaFcP1mZ5_14pauth_extern_c7call_it(ptr ptrauth (ptr @external_c_callee, i32 0), i32 5, i32 7) | |
| 36 | // O3_PAUTH: call{{.*}}_RNvCshUtaFcP1mZ5_14pauth_extern_c7call_it(ptr{{.*}}ptrauth (ptr @external_c_callee, i32 0), i32{{.*}}5, i32{{.*}}7) | |
| 37 | let _ = call_it(external_c_callee, 5, 7); | |
| 38 | } | |
| 39 | ||
| 40 | // O0_PAUTH: define {{.*}}pauth_extern_c7call_it{{.*}} #[[ATTR_O0_1:[0-9]+]] | |
| 41 | // O3_PAUTH: define {{.*}}pauth_extern_c7call_it{{.*}} #[[ATTR_O3_1:[0-9]+]] | |
| 42 | #[inline(never)] | |
| 43 | pub fn call_it(fn_ptr: FnPtr, arg_1: i32, arg_2: i32) -> i32 { | |
| 44 | // O0_PAUTH: call i32 %fn_ptr(i32 %arg_1, i32 %arg_2){{.*}}[ "ptrauth"(i32 0, i64 0) ] | |
| 45 | // O3_PAUTH: call{{.*}}i32 %fn_ptr(i32{{.*}}%arg_1, i32{{.*}}%arg_2){{.*}}[ "ptrauth"(i32 0, i64 0) ] | |
| 46 | unsafe { fn_ptr(arg_1, arg_2) } | |
| 47 | } | |
| 48 | ||
| 49 | extern "C" { | |
| 50 | fn external_c_callee(a: i32, b: i32) -> i32; | |
| 51 | } | |
| 52 | ||
| 53 | // O0_PAUTH-CHECK: attributes #[[ATTR_O0_1]] = { {{.*}}"aarch64-jump-table-hardening" | |
| 54 | // O0_PAUTH-CHECK-SAME: "ptrauth-auth-traps" | |
| 55 | // O0_PAUTH-CHECK-SAME: "ptrauth-calls" | |
| 56 | // O0_PAUTH-CHECK-SAME: "ptrauth-indirect-gotos" | |
| 57 | // O0_PAUTH-CHECK-SAME: "ptrauth-returns" | |
| 58 | ||
| 59 | // O3_PAUTH-CHECK: attributes #[[ATTR_O3_1]] = { {{.*}}"aarch64-jump-table-hardening" | |
| 60 | // O3_PAUTH-CHECK-SAME: "ptrauth-auth-traps" | |
| 61 | // O3_PAUTH-CHECK-SAME: "ptrauth-calls" | |
| 62 | // O3_PAUTH-CHECK-SAME: "ptrauth-indirect-gotos" | |
| 63 | // O3_PAUTH-CHECK-SAME: "ptrauth-returns" | |
| 64 | ||
| 65 | // O0_PAUTH-ELF-GOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} | |
| 66 | // O0_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} | |
| 67 | // O0_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} | |
| 68 | // O3_PAUTH-ELF-GOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} | |
| 69 | // O3_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} | |
| 70 | // O3_PAUTH: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} | |
| 71 | ||
| 72 | // O0_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} | |
| 73 | // O0_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} | |
| 74 | // O3_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-elf-got", i32 1} | |
| 75 | // O3_NO_PAUTH-NOT: !{{[0-9]+}} = !{i32 1, !"ptrauth-sign-personality", i32 1} |
tests/codegen-llvm/pauth/pauth-extern-weak-global.rs created+38| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | // ignore-tidy-linelength | |
| 2 | //@ only-pauthtest | |
| 3 | //@ revisions: O0_PAUTH O3_PAUTH O0_NO_PAUTH O3_NO_PAUTH | |
| 4 | //@ add-minicore | |
| 5 | ||
| 6 | //@ [O0_PAUTH] needs-llvm-components: aarch64 | |
| 7 | //@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 | |
| 8 | //@ [O3_PAUTH] needs-llvm-components: aarch64 | |
| 9 | //@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 | |
| 10 | //@ [O0_NO_PAUTH] needs-llvm-components: aarch64 | |
| 11 | //@ [O0_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=0 | |
| 12 | //@ [O3_NO_PAUTH] needs-llvm-components: aarch64 | |
| 13 | //@ [O3_NO_PAUTH] compile-flags: --target=aarch64-unknown-linux-gnu -C opt-level=3 | |
| 14 | ||
| 15 | #![crate_type = "lib"] | |
| 16 | #![no_std] | |
| 17 | #![no_core] | |
| 18 | #![feature(no_core)] | |
| 19 | #![feature(linkage)] | |
| 20 | ||
| 21 | extern crate minicore; | |
| 22 | use minicore::*; | |
| 23 | ||
| 24 | // O0_PAUTH: @{{[0-9A-Za-z_]+}}FUNCTION_PTR_DECL = constant ptr ptrauth (ptr @extern_weak_fn, i32 0) | |
| 25 | // O0_PAUTH: declare i64 @extern_weak_fn({{.*}}) | |
| 26 | // O3_PAUTH: @{{[0-9A-Za-z_]+}}FUNCTION_PTR_DECL = constant ptr ptrauth (ptr @extern_weak_fn, i32 0) | |
| 27 | // O3_PAUTH: declare {{.*}} i64 @extern_weak_fn({{.*}}) | |
| 28 | // | |
| 29 | // O0_NO_PAUTH-NOT: ptr ptrauth | |
| 30 | // O3_NO_PAUTH-NOT: ptr ptrauth | |
| 31 | extern "C" { | |
| 32 | #[link_name = "extern_weak_fn"] | |
| 33 | #[linkage = "extern_weak"] | |
| 34 | fn extern_weak_fn() -> i64; | |
| 35 | } | |
| 36 | ||
| 37 | #[used] | |
| 38 | static FUNCTION_PTR_DECL: unsafe extern "C" fn() -> i64 = extern_weak_fn; |
tests/codegen-llvm/pauth/pauth-init-fini.rs created+34| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | //@ add-minicore | |
| 2 | // ignore-tidy-linelength | |
| 3 | //@ only-pauthtest | |
| 4 | //@ revisions: O0_PAUTH O3_PAUTH | |
| 5 | ||
| 6 | //@ [O0_PAUTH] needs-llvm-components: aarch64 | |
| 7 | //@ [O0_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=0 | |
| 8 | //@ [O3_PAUTH] needs-llvm-components: aarch64 | |
| 9 | //@ [O3_PAUTH] compile-flags: --target=aarch64-unknown-linux-pauthtest -C opt-level=3 | |
| 10 | ||
| 11 | // Make sure that init/fini metadata uses correct discriminator: 0xd9d4/55764 | |
| 12 | ||
| 13 | #![feature(no_core, lang_items)] | |
| 14 | #![no_std] | |
| 15 | #![no_core] | |
| 16 | #![crate_type = "lib"] | |
| 17 | ||
| 18 | extern crate minicore; | |
| 19 | use minicore::*; | |
| 20 | ||
| 21 | // O0_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" | |
| 22 | // O3_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_INIT = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}init_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".init_array.90" | |
| 23 | #[used] | |
| 24 | #[link_section = ".init_array.90"] | |
| 25 | static GLOBAL_INIT: extern "C" fn() = init_fn; | |
| 26 | ||
| 27 | // O0_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" | |
| 28 | // O3_PAUTH: @{{[0-9A-Za-z_]+}}GLOBAL_FINI = constant ptr ptrauth (ptr @{{[0-9A-Za-z_]+}}fini_fn, i32 0, i64 55764, ptr inttoptr (i64 1 to ptr)), section ".fini_array.90" | |
| 29 | #[used] | |
| 30 | #[link_section = ".fini_array.90"] | |
| 31 | static GLOBAL_FINI: extern "C" fn(i32) = fini_fn; | |
| 32 | ||
| 33 | extern "C" fn init_fn() {} | |
| 34 | extern "C" fn fini_fn(_: i32) {} |
tests/run-make/c-link-to-rust-va-list-fn/rmake.rs+2| ... | ... | @@ -6,6 +6,8 @@ |
| 6 | 6 | //@ needs-target-std |
| 7 | 7 | //@ ignore-android: FIXME(#142855) |
| 8 | 8 | //@ ignore-sgx: (x86 machine code cannot be directly executed) |
| 9 | //@ ignore-pauthtest: (it requires non-trivial compilation of c sources, and only supports dynamic | |
| 10 | // linking, ignore the test). | |
| 9 | 11 | |
| 10 | 12 | use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; |
| 11 | 13 |
tests/run-make/pauth-quicksort-c-driver/main.c created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | #include <stdint.h> | |
| 2 | #include <stdio.h> | |
| 3 | ||
| 4 | #define NUM_ELEMS 5 | |
| 5 | ||
| 6 | void quickSort(void *Base, size_t N, size_t Size, | |
| 7 | int (*Cmp)(const void *, const void *)); | |
| 8 | ||
| 9 | #ifdef __cplusplus | |
| 10 | } | |
| 11 | #endif | |
| 12 | ||
| 13 | int cmpI32Ascending(const void *LHS, const void *RHS) { | |
| 14 | int32_t x = *(const int32_t *)LHS; | |
| 15 | int32_t y = *(const int32_t *)RHS; | |
| 16 | ||
| 17 | if (x < y) | |
| 18 | return -1; | |
| 19 | else if (x > y) | |
| 20 | return 1; | |
| 21 | else | |
| 22 | return 0; | |
| 23 | } | |
| 24 | ||
| 25 | int main() { | |
| 26 | int32_t Data[NUM_ELEMS] = {4, 2, 5, 3, 1}; | |
| 27 | ||
| 28 | printf("Before sorting: "); | |
| 29 | for (int i = 0; i < NUM_ELEMS; i++) | |
| 30 | printf("%d ", Data[i]); | |
| 31 | printf("\n"); | |
| 32 | ||
| 33 | quickSort(Data, NUM_ELEMS, sizeof(int32_t), cmpI32Ascending); | |
| 34 | ||
| 35 | printf("After sorting: "); | |
| 36 | for (int i = 0; i < NUM_ELEMS; i++) | |
| 37 | printf("%d ", Data[i]); | |
| 38 | printf("\n"); | |
| 39 | ||
| 40 | for (size_t i = 1; i < NUM_ELEMS; i++) | |
| 41 | if (Data[i - 1] > Data[i]) | |
| 42 | return 42; | |
| 43 | ||
| 44 | return 0; | |
| 45 | } |
tests/run-make/pauth-quicksort-c-driver/quicksort.rs created+66| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | use std::mem::size_of; | |
| 2 | use std::os::raw::{c_int, c_void}; | |
| 3 | use std::ptr; | |
| 4 | ||
| 5 | unsafe fn swap_i32(lhs: *mut i32, rhs: *mut i32) { | |
| 6 | ptr::swap(lhs, rhs); | |
| 7 | } | |
| 8 | ||
| 9 | unsafe fn partition( | |
| 10 | arr: *mut i32, | |
| 11 | low: isize, | |
| 12 | high: isize, | |
| 13 | cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, | |
| 14 | ) -> isize { | |
| 15 | let pivot = arr.offset(low); | |
| 16 | let mut i = low; | |
| 17 | let mut j = high; | |
| 18 | ||
| 19 | while i < j { | |
| 20 | while i <= high - 1 && cmp(arr.offset(i) as *const c_void, pivot as *const c_void) <= 0 { | |
| 21 | i += 1; | |
| 22 | } | |
| 23 | ||
| 24 | while j >= low + 1 && cmp(arr.offset(j) as *const c_void, pivot as *const c_void) > 0 { | |
| 25 | j -= 1; | |
| 26 | } | |
| 27 | ||
| 28 | if i < j { | |
| 29 | swap_i32(arr.offset(i), arr.offset(j)); | |
| 30 | } | |
| 31 | } | |
| 32 | ||
| 33 | swap_i32(arr.offset(low), arr.offset(j)); | |
| 34 | j | |
| 35 | } | |
| 36 | ||
| 37 | unsafe fn quicksort_rec( | |
| 38 | arr: *mut i32, | |
| 39 | low: isize, | |
| 40 | high: isize, | |
| 41 | cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, | |
| 42 | ) { | |
| 43 | if low < high { | |
| 44 | let part = partition(arr, low, high, cmp); | |
| 45 | quicksort_rec(arr, low, part - 1, cmp); | |
| 46 | quicksort_rec(arr, part + 1, high, cmp); | |
| 47 | } | |
| 48 | } | |
| 49 | ||
| 50 | #[no_mangle] | |
| 51 | pub extern "C" fn quickSort( | |
| 52 | base: *mut c_void, | |
| 53 | n: usize, | |
| 54 | size: usize, | |
| 55 | cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, | |
| 56 | ) { | |
| 57 | if size != size_of::<i32>() { | |
| 58 | std::process::abort(); | |
| 59 | } | |
| 60 | ||
| 61 | if n > 1 { | |
| 62 | unsafe { | |
| 63 | quicksort_rec(base as *mut i32, 0, (n as isize) - 1, cmp); | |
| 64 | } | |
| 65 | } | |
| 66 | } |
tests/run-make/pauth-quicksort-c-driver/rmake.rs created+42| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | // Test compilation flow using custom pauth-enabled toolchain and signing extern "C" function | |
| 2 | // pointers used from within rust. The test assumes that pointer-authentication-enabled `clang` is | |
| 3 | // available on the path. In this test rust is the driver - providing the data and the comparison | |
| 4 | // function; while c - provides the implementation of quicksort algorithm and is the user of the | |
| 5 | // data and comparator. | |
| 6 | ||
| 7 | //@ only-pauthtest | |
| 8 | ||
| 9 | use run_make_support::{cc, env_var, rfs, run, run_fail, rustc}; | |
| 10 | ||
| 11 | fn main() { | |
| 12 | // Use CC and CC_DEFAULT_FLAGS env variables to set up linker for rustc. This results in the | |
| 13 | // same command as cc(). The CC env variable corresponds to cc field in the config toml file. | |
| 14 | // This field is required to point to a clang family compiler on aarch64-unknown-linux-pauthtest | |
| 15 | // target. | |
| 16 | let rust_lib_name = "rust_quicksort"; | |
| 17 | rustc() | |
| 18 | .target("aarch64-unknown-linux-pauthtest") | |
| 19 | .crate_type("cdylib") | |
| 20 | .input("quicksort.rs") | |
| 21 | .linker(&env_var("CC")) | |
| 22 | .link_args(&env_var("CC_DEFAULT_FLAGS")) | |
| 23 | .crate_name(rust_lib_name) | |
| 24 | .run(); | |
| 25 | ||
| 26 | let exe_name = "main"; | |
| 27 | cc().out_exe(exe_name) | |
| 28 | .input("main.c") | |
| 29 | .args(&[ | |
| 30 | "-march=armv8.3-a+pauth", | |
| 31 | "-target", | |
| 32 | "aarch64-unknown-linux-pauthtest", | |
| 33 | &format!("-l{}", rust_lib_name), | |
| 34 | ]) | |
| 35 | .library_search_path(".") | |
| 36 | .run(); | |
| 37 | ||
| 38 | run(exe_name); | |
| 39 | ||
| 40 | rfs::remove_file(format!("{}{rust_lib_name}.{}", "lib", "so")); | |
| 41 | run_fail(exe_name); | |
| 42 | } |
tests/run-make/pauth-quicksort-rust-driver/main.rs created+43| ... | ... | @@ -0,0 +1,43 @@ |
| 1 | use std::os::raw::{c_int, c_void}; | |
| 2 | ||
| 3 | #[link(name = "quicksort")] | |
| 4 | extern "C" { | |
| 5 | fn quickSort( | |
| 6 | base: *mut c_void, | |
| 7 | n: usize, | |
| 8 | size: usize, | |
| 9 | cmp: extern "C" fn(*const c_void, *const c_void) -> c_int, | |
| 10 | ); | |
| 11 | } | |
| 12 | ||
| 13 | extern "C" fn cmp_i32_ascending(a: *const c_void, b: *const c_void) -> c_int { | |
| 14 | unsafe { | |
| 15 | let x = *(a as *const i32); | |
| 16 | let y = *(b as *const i32); | |
| 17 | ||
| 18 | if x < y { | |
| 19 | -1 | |
| 20 | } else if x > y { | |
| 21 | 1 | |
| 22 | } else { | |
| 23 | 0 | |
| 24 | } | |
| 25 | } | |
| 26 | } | |
| 27 | ||
| 28 | fn main() { | |
| 29 | let mut data: [i32; 5] = [4, 2, 5, 3, 1]; | |
| 30 | println!("Before sorting: {:?}", data); | |
| 31 | ||
| 32 | unsafe { | |
| 33 | quickSort( | |
| 34 | data.as_mut_ptr() as *mut c_void, | |
| 35 | data.len(), | |
| 36 | std::mem::size_of::<i32>(), | |
| 37 | cmp_i32_ascending, | |
| 38 | ); | |
| 39 | } | |
| 40 | ||
| 41 | println!("After sorting: {:?}", data); | |
| 42 | assert!(data.windows(2).all(|w| w[0] <= w[1])); | |
| 43 | } |
tests/run-make/pauth-quicksort-rust-driver/quicksort.c created+50| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | #include <stdint.h> | |
| 2 | #include <stdlib.h> | |
| 3 | #include <string.h> | |
| 4 | ||
| 5 | void swap(void *A, void *B, size_t Size) { | |
| 6 | unsigned char Tmp[Size]; | |
| 7 | memcpy(Tmp, A, Size); | |
| 8 | memcpy(A, B, Size); | |
| 9 | memcpy(B, Tmp, Size); | |
| 10 | } | |
| 11 | ||
| 12 | int partition(void *Base, int Low, int High, size_t Size, | |
| 13 | int (*Cmp)(const void *, const void *)) { | |
| 14 | char *Arr = (char *)Base; | |
| 15 | ||
| 16 | void *Pivot = Arr + Low * Size; | |
| 17 | int i = Low; | |
| 18 | int j = High; | |
| 19 | ||
| 20 | while (i < j) { | |
| 21 | while (i <= High - 1 && Cmp(Arr + i * Size, Pivot) <= 0) | |
| 22 | i++; | |
| 23 | ||
| 24 | while (j >= Low + 1 && Cmp(Arr + j * Size, Pivot) > 0) | |
| 25 | j--; | |
| 26 | ||
| 27 | if (i < j) | |
| 28 | swap(Arr + i * Size, Arr + j * Size, Size); | |
| 29 | } | |
| 30 | ||
| 31 | swap(Arr + Low * Size, Arr + j * Size, Size); | |
| 32 | return j; | |
| 33 | } | |
| 34 | ||
| 35 | void quickSortRec(void *Base, int Low, int High, size_t Size, | |
| 36 | int (*Cmp)(const void *, const void *)) { | |
| 37 | if (Low < High) { | |
| 38 | int Part = partition(Base, Low, High, Size, Cmp); | |
| 39 | quickSortRec(Base, Low, Part - 1, Size, Cmp); | |
| 40 | quickSortRec(Base, Part + 1, High, Size, Cmp); | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | void quickSort(void *Base, size_t N, size_t Size, | |
| 45 | int (*Cmp)(const void *, const void *)) { | |
| 46 | if (Size != sizeof(int32_t)) | |
| 47 | abort(); | |
| 48 | if (N > 1) | |
| 49 | quickSortRec(Base, 0, (int)N - 1, Size, Cmp); | |
| 50 | } |
tests/run-make/pauth-quicksort-rust-driver/rmake.rs created+34| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | // Test compilation flow using custom pauth-enabled toolchain and signing extern "C" function | |
| 2 | // pointers used from within rust. The test assumes that pointer-authentication-enabled `clang` is | |
| 3 | // available on the path. | |
| 4 | // In this test rust is the driver - providing the data and the comparison function; while c - | |
| 5 | // provides the implementation of quicksort algorithm and is the user of the data and comparator. | |
| 6 | ||
| 7 | //@ only-pauthtest | |
| 8 | ||
| 9 | use run_make_support::{cc, env_var, rfs, run, run_fail, rustc}; | |
| 10 | ||
| 11 | fn main() { | |
| 12 | let input = "quicksort"; | |
| 13 | let input_name = format!("{input}.c"); | |
| 14 | let lib_name = format!("{}{input}.{}", "lib", "so"); | |
| 15 | cc().out_exe(&lib_name) | |
| 16 | .input(&input_name) | |
| 17 | .args(&["-target", "aarch64-unknown-linux-pauthtest", "-march=armv8.3-a+pauth", "-shared"]) | |
| 18 | .run(); | |
| 19 | ||
| 20 | // Use CC and CC_DEFAULT_FLAGS env variables to set up linker for rustc. This results in the | |
| 21 | // same command as cc(). The CC env variable corresponds to cc field in the config toml file. | |
| 22 | // This field is required to point to a clang family compiler on aarch64-unknown-linux-pauthtest | |
| 23 | // target. | |
| 24 | rustc() | |
| 25 | .target("aarch64-unknown-linux-pauthtest") | |
| 26 | .input("main.rs") | |
| 27 | .linker(&env_var("CC")) | |
| 28 | .link_args(&env_var("CC_DEFAULT_FLAGS")) | |
| 29 | .run(); | |
| 30 | run("main"); | |
| 31 | ||
| 32 | rfs::remove_file(&lib_name); | |
| 33 | run_fail("main"); | |
| 34 | } |
tests/run-make/pauth-static-link-warning/helper.c created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | int helper_function() { return 42; } |
tests/run-make/pauth-static-link-warning/main.rs created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | #[link(name = "helper", kind = "static")] | |
| 2 | extern "C" { | |
| 3 | fn helper_function() -> i32; | |
| 4 | } | |
| 5 | ||
| 6 | fn main() { | |
| 7 | unsafe { | |
| 8 | assert!(42 == helper_function()); | |
| 9 | } | |
| 10 | } |
tests/run-make/pauth-static-link-warning/main_cmd_line.rs created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | extern "C" { | |
| 2 | fn helper_function() -> i32; | |
| 3 | } | |
| 4 | ||
| 5 | fn main() { | |
| 6 | unsafe { | |
| 7 | assert!(42 == helper_function()); | |
| 8 | } | |
| 9 | } |
tests/run-make/pauth-static-link-warning/rmake.rs created+46| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | // Make sure that for `aarch64-unknown-linux-pauthtest` compiler emits warning when static | |
| 2 | // libraries are linked. Test both foreign module linked from #[link] directive and command line | |
| 3 | // invocations. | |
| 4 | ||
| 5 | //@ only-pauthtest | |
| 6 | // ignore-tidy-linelength | |
| 7 | ||
| 8 | use run_make_support::{cc, env_var, regex, run, rustc}; | |
| 9 | ||
| 10 | fn main() { | |
| 11 | let input = "helper"; | |
| 12 | let input_name = format!("{input}.c"); | |
| 13 | let lib_name = format!("{}{input}.{}", "lib", "a"); | |
| 14 | // Build a static library | |
| 15 | cc().out_exe(&lib_name) | |
| 16 | .input(&input_name) | |
| 17 | .args(&["-target", "aarch64-unknown-linux-pauthtest", "-march=armv8.3-a+pauth", "-c"]) | |
| 18 | .run(); | |
| 19 | ||
| 20 | // Check against foreign module warning: #[link(name = "helper", kind = "static")] | |
| 21 | let stderr_foreign_module = rustc() | |
| 22 | .target("aarch64-unknown-linux-pauthtest") | |
| 23 | .input("main.rs") | |
| 24 | .linker(&env_var("CC")) | |
| 25 | .link_args(&env_var("CC_DEFAULT_FLAGS")) | |
| 26 | .arg("-L.") | |
| 27 | .run() | |
| 28 | .stderr_utf8(); | |
| 29 | run("main"); | |
| 30 | let re_foreign_moule = regex::Regex::new( r"(?s)warning: library `helper`.*linked statically.*aarch64-unknown-linux-pauthtest.*requires dynamic linking.*using dynamic linking instead").unwrap(); | |
| 31 | assert!(re_foreign_moule.is_match(&stderr_foreign_module)); | |
| 32 | ||
| 33 | // Check against command line warning: -lstatic=helper | |
| 34 | let stderr_command_line = rustc() | |
| 35 | .target("aarch64-unknown-linux-pauthtest") | |
| 36 | .input("main_cmd_line.rs") | |
| 37 | .linker(&env_var("CC")) | |
| 38 | .link_args(&env_var("CC_DEFAULT_FLAGS")) | |
| 39 | .arg("-L.") | |
| 40 | .arg("-lstatic=helper") | |
| 41 | .run() | |
| 42 | .stderr_utf8(); | |
| 43 | run("main_cmd_line"); | |
| 44 | let re_cmd_line = regex::Regex::new( r"(?s)warning: static linking of `helper`.*is not supported on.*aarch64-unknown-linux-pauthtest.*using dynamic linking instead").unwrap(); | |
| 45 | assert!(re_cmd_line.is_match(&stderr_command_line)); | |
| 46 | } |
tests/run-make/rustdoc-test-builder/rmake.rs+1| ... | ... | @@ -27,6 +27,7 @@ fn main() { |
| 27 | 27 | // so only exercise the success path when the target can run on the host. |
| 28 | 28 | if target().contains("wasm") |
| 29 | 29 | || target().contains("sgx") |
| 30 | || target().contains("pauthtest") | |
| 30 | 31 | || std::env::var_os("REMOTE_TEST_CLIENT").is_some() |
| 31 | 32 | { |
| 32 | 33 | return; |
tests/run-make/wasm-compiler-builtins-object-arch/rmake.rs created+54| ... | ... | @@ -0,0 +1,54 @@ |
| 1 | //! Regression test for <https://github.com/rust-lang/rust/issues/132802>. | |
| 2 | //! | |
| 3 | //! The prebuilt `libcompiler_builtins` rlib bundled in the wasm sysroot must | |
| 4 | //! contain wasm object files — never host ELF/Mach-O/COFF. Bootstrap could | |
| 5 | //! previously pick the host C toolchain for compiler-rt fallbacks on wasm | |
| 6 | //! targets and silently embed host objects into the wasm sysroot | |
| 7 | //! (fixed in rust-lang/rust#137457). | |
| 8 | ||
| 9 | //@ only-wasm32 | |
| 10 | ||
| 11 | use run_make_support::object::read::Object; | |
| 12 | use run_make_support::object::read::archive::ArchiveFile; | |
| 13 | use run_make_support::object::{self, Architecture}; | |
| 14 | use run_make_support::{has_extension, has_prefix, rfs, rustc, shallow_find_files}; | |
| 15 | ||
| 16 | fn main() { | |
| 17 | let libdir = rustc().print("target-libdir").run().stdout_utf8(); | |
| 18 | let libdir = libdir.trim(); | |
| 19 | ||
| 20 | let rlibs = shallow_find_files(libdir, |path| { | |
| 21 | has_prefix(path, "libcompiler_builtins") && has_extension(path, "rlib") | |
| 22 | }); | |
| 23 | assert!(!rlibs.is_empty(), "no libcompiler_builtins rlib found in {libdir}"); | |
| 24 | ||
| 25 | let data = rfs::read(&rlibs[0]); | |
| 26 | let archive = ArchiveFile::parse(&*data).unwrap(); | |
| 27 | ||
| 28 | let mut checked = 0usize; | |
| 29 | for member in archive.members() { | |
| 30 | let member = member.unwrap(); | |
| 31 | let name = std::str::from_utf8(member.name()).unwrap_or("<invalid-utf8>"); | |
| 32 | if name.ends_with(".rmeta") || name.ends_with(".rmeta-link") { | |
| 33 | continue; | |
| 34 | } | |
| 35 | let obj_data = member.data(&*data).unwrap(); | |
| 36 | let obj = object::File::parse(obj_data).unwrap_or_else(|e| { | |
| 37 | panic!("failed to parse member `{name}` in compiler_builtins rlib: {e}") | |
| 38 | }); | |
| 39 | let arch = obj.architecture(); | |
| 40 | assert!( | |
| 41 | matches!(arch, Architecture::Wasm32 | Architecture::Wasm64), | |
| 42 | "object `{name}` in compiler_builtins rlib has architecture {arch:?}, \ | |
| 43 | expected wasm — see rust-lang/rust#132802", | |
| 44 | ); | |
| 45 | checked += 1; | |
| 46 | } | |
| 47 | ||
| 48 | assert!( | |
| 49 | checked > 0, | |
| 50 | "no object members found in compiler_builtins rlib at {} — \ | |
| 51 | archive should always contain object files", | |
| 52 | rlibs[0].display(), | |
| 53 | ); | |
| 54 | } |
tests/rustdoc-json/attrs/stability/default_body.rs created+76| ... | ... | @@ -0,0 +1,76 @@ |
| 1 | #![feature(staged_api, rustc_attrs, associated_type_defaults)] | |
| 2 | ||
| 3 | #[stable(feature = "default_body_trait_feature", since = "1.0.0")] | |
| 4 | pub trait TraitWithDefaults { | |
| 5 | //@ is "$.index[?(@.docs=='method with unstable default body')].inner.function.has_body" true | |
| 6 | //@ is "$.index[?(@.docs=='method with unstable default body')].inner.function.default_unstable.feature" '"method_default_body_feature"' | |
| 7 | //@ is "$.index[?(@.docs=='method with unstable default body')].attrs" [] | |
| 8 | /// method with unstable default body | |
| 9 | #[stable(feature = "default_body_method_feature", since = "1.1.0")] | |
| 10 | #[rustc_default_body_unstable(feature = "method_default_body_feature", issue = "none")] | |
| 11 | fn method_with_unstable_default() {} | |
| 12 | ||
| 13 | //@ is "$.index[?(@.docs=='required method without default body')].inner.function.has_body" false | |
| 14 | //@ is "$.index[?(@.docs=='required method without default body')].inner.function.default_unstable" null | |
| 15 | /// required method without default body | |
| 16 | #[stable(feature = "required_method_feature", since = "1.2.0")] | |
| 17 | fn required_method(); | |
| 18 | ||
| 19 | //@ is "$.index[?(@.docs=='method with stable default body')].inner.function.has_body" true | |
| 20 | //@ is "$.index[?(@.docs=='method with stable default body')].inner.function.default_unstable" null | |
| 21 | /// method with stable default body | |
| 22 | #[stable(feature = "stable_default_method_feature", since = "1.3.0")] | |
| 23 | fn method_with_stable_default() {} | |
| 24 | ||
| 25 | //@ is "$.index[?(@.docs=='associated constant with unstable default value')].inner.assoc_const.value" '"0"' | |
| 26 | //@ is "$.index[?(@.docs=='associated constant with unstable default value')].inner.assoc_const.default_unstable.feature" '"assoc_const_default_value_feature"' | |
| 27 | //@ is "$.index[?(@.docs=='associated constant with unstable default value')].attrs" [] | |
| 28 | /// associated constant with unstable default value | |
| 29 | #[stable(feature = "assoc_const_with_unstable_default_feature", since = "1.4.0")] | |
| 30 | #[rustc_default_body_unstable(feature = "assoc_const_default_value_feature", issue = "none")] | |
| 31 | const UNSTABLE_DEFAULT_CONST: usize = 0; | |
| 32 | ||
| 33 | //@ is "$.index[?(@.docs=='required associated constant')].inner.assoc_const.value" null | |
| 34 | //@ is "$.index[?(@.docs=='required associated constant')].inner.assoc_const.default_unstable" null | |
| 35 | /// required associated constant | |
| 36 | #[stable(feature = "required_assoc_const_feature", since = "1.5.0")] | |
| 37 | const REQUIRED_CONST: usize; | |
| 38 | ||
| 39 | //@ is "$.index[?(@.docs=='associated type with unstable default type')].inner.assoc_type.default_unstable.feature" '"assoc_type_default_type_feature"' | |
| 40 | //@ is "$.index[?(@.docs=='associated type with unstable default type')].attrs" [] | |
| 41 | /// associated type with unstable default type | |
| 42 | #[stable(feature = "assoc_type_with_unstable_default_feature", since = "1.6.0")] | |
| 43 | #[rustc_default_body_unstable(feature = "assoc_type_default_type_feature", issue = "none")] | |
| 44 | type UnstableDefaultType = usize; | |
| 45 | ||
| 46 | //@ is "$.index[?(@.docs=='required associated type')].inner.assoc_type.type" null | |
| 47 | //@ is "$.index[?(@.docs=='required associated type')].inner.assoc_type.default_unstable" null | |
| 48 | /// required associated type | |
| 49 | #[stable(feature = "required_assoc_type_feature", since = "1.7.0")] | |
| 50 | type RequiredType; | |
| 51 | } | |
| 52 | ||
| 53 | #[stable(feature = "default_body_impl_target_feature", since = "2.0.0")] | |
| 54 | pub struct ImplTarget; | |
| 55 | ||
| 56 | // Impl items provide their own definitions, so they do not use the trait's unstable defaults. | |
| 57 | #[stable(feature = "default_body_impl_feature", since = "2.1.0")] | |
| 58 | impl TraitWithDefaults for ImplTarget { | |
| 59 | //@ is "$.index[?(@.docs=='impl override for unstable default body')].inner.function.default_unstable" null | |
| 60 | /// impl override for unstable default body | |
| 61 | fn method_with_unstable_default() {} | |
| 62 | ||
| 63 | fn required_method() {} | |
| 64 | ||
| 65 | //@ is "$.index[?(@.docs=='impl override for unstable default value')].inner.assoc_const.default_unstable" null | |
| 66 | /// impl override for unstable default value | |
| 67 | const UNSTABLE_DEFAULT_CONST: usize = 1; | |
| 68 | ||
| 69 | const REQUIRED_CONST: usize = 2; | |
| 70 | ||
| 71 | //@ is "$.index[?(@.docs=='impl override for unstable default type')].inner.assoc_type.default_unstable" null | |
| 72 | /// impl override for unstable default type | |
| 73 | type UnstableDefaultType = u8; | |
| 74 | ||
| 75 | type RequiredType = (); | |
| 76 | } |
tests/ui/check-cfg/well-known-values.stderr+1-1| ... | ... | @@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` |
| 129 | 129 | LL | target_abi = "_UNEXPECTED_VALUE", |
| 130 | 130 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 131 | 131 | | |
| 132 | = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elfv1`, `elfv2`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` | |
| 132 | = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elfv1`, `elfv2`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `pauthtest`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32` | |
| 133 | 133 | = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration |
| 134 | 134 | |
| 135 | 135 | warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` |
tests/ui/codegen/huge-stacks.rs+2-1| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | //@ min-llvm-version: 22 |
| 6 | 6 | |
| 7 | 7 | // Regression test for https://github.com/rust-lang/rust/issues/83060 |
| 8 | // Verifies a program is not miscompiled if it includes a 4GB array on the stack | |
| 8 | 9 | |
| 9 | 10 | fn func() { |
| 10 | 11 | const CAP: usize = std::u32::MAX as usize; |
| ... | ... | @@ -17,7 +18,7 @@ fn main() { |
| 17 | 18 | std::thread::Builder::new() |
| 18 | 19 | .stack_size(5 * 1024 * 1024 * 1024) |
| 19 | 20 | .spawn(func) |
| 20 | .unwrap() | |
| 21 | .expect("huge-stacks.rs requires 5GB RAM to run") | |
| 21 | 22 | .join() |
| 22 | 23 | .unwrap(); |
| 23 | 24 | } |
tests/ui/const-generics/mgca/double-inline-const.rs created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | #![feature(min_generic_const_args)] | |
| 2 | ||
| 3 | struct S<const N: usize>; | |
| 4 | ||
| 5 | impl<const N: usize> S<N> { | |
| 6 | const Q: usize = 2; | |
| 7 | fn foo(_: S<{ const { const { Self::Q } } }>) {} | |
| 8 | //~^ ERROR generic `Self` types are currently not permitted in anonymous constants | |
| 9 | } | |
| 10 | ||
| 11 | fn main() {} |
tests/ui/const-generics/mgca/double-inline-const.stderr created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | error: generic `Self` types are currently not permitted in anonymous constants | |
| 2 | --> $DIR/double-inline-const.rs:7:35 | |
| 3 | | | |
| 4 | LL | fn foo(_: S<{ const { const { Self::Q } } }>) {} | |
| 5 | | ^^^^ | |
| 6 | | | |
| 7 | note: not a concrete type | |
| 8 | --> $DIR/double-inline-const.rs:5:22 | |
| 9 | | | |
| 10 | LL | impl<const N: usize> S<N> { | |
| 11 | | ^^^^ | |
| 12 | = help: add `#![feature(generic_const_args)]` to allow generic expressions as the RHS of const items | |
| 13 | ||
| 14 | error: aborting due to 1 previous error | |
| 15 |
tests/ui/process/nofile-limit.rs+3| ... | ... | @@ -8,6 +8,9 @@ |
| 8 | 8 | //@ no-prefer-dynamic |
| 9 | 9 | //@ compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static |
| 10 | 10 | //@ ignore-backends: gcc |
| 11 | // aarch64-unknown-linux-pauthtest requires dynamic linking, which makes use of file descriptors. | |
| 12 | // Setting RLIMIT_NOFILE would result in the binary failing even before main is reached. | |
| 13 | //@ ignore-pauthtest | |
| 11 | 14 | |
| 12 | 15 | #![feature(exit_status_error)] |
| 13 | 16 | #![feature(rustc_private)] |
tests/ui/statics/crt-static-pauthtest.rs created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | //@ compile-flags: -C target-feature=+crt-static --target aarch64-unknown-linux-pauthtest | |
| 2 | //@ needs-llvm-components: aarch64 | |
| 3 | //@ only-pauthtest | |
| 4 | ||
| 5 | ||
| 6 | #![feature(no_core)] | |
| 7 | #![no_main] | |
| 8 | ||
| 9 | //~? ERROR pointer authentication requires dynamic linking. Statically linked libc is incompatible, disable it using `-C target-feature=-crt-static` |
tests/ui/statics/crt-static-pauthtest.stderr created+4| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | error: pointer authentication requires dynamic linking. Statically linked libc is incompatible, disable it using `-C target-feature=-crt-static` | |
| 2 | ||
| 3 | error: aborting due to 1 previous error | |
| 4 |
tests/ui/traits/next-solver/deferred-closure-call-recovery-issue-157951.rs created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | //@ compile-flags: -Znext-solver=globally | |
| 2 | //@ check-fail | |
| 3 | ||
| 4 | fn main() { | |
| 5 | let f = |f: dyn Fn()| f; | |
| 6 | //~^ ERROR the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time | |
| 7 | //~| ERROR return type cannot be a trait object without pointer indirection | |
| 8 | f(); | |
| 9 | //~^ ERROR this function takes 1 argument but 0 arguments were supplied | |
| 10 | } |
tests/ui/traits/next-solver/deferred-closure-call-recovery-issue-157951.stderr created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | error[E0277]: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time | |
| 2 | --> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:17 | |
| 3 | | | |
| 4 | LL | let f = |f: dyn Fn()| f; | |
| 5 | | ^^^^^^^^ doesn't have a size known at compile-time | |
| 6 | | | |
| 7 | = help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)` | |
| 8 | = help: unsized fn params are gated as an unstable feature | |
| 9 | help: function arguments must have a statically known size, borrowed types always have a known size | |
| 10 | | | |
| 11 | LL | let f = |f: &dyn Fn()| f; | |
| 12 | | + | |
| 13 | ||
| 14 | error[E0746]: return type cannot be a trait object without pointer indirection | |
| 15 | --> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:27 | |
| 16 | | | |
| 17 | LL | let f = |f: dyn Fn()| f; | |
| 18 | | ^ doesn't have a size known at compile-time | |
| 19 | ||
| 20 | error[E0057]: this function takes 1 argument but 0 arguments were supplied | |
| 21 | --> $DIR/deferred-closure-call-recovery-issue-157951.rs:8:5 | |
| 22 | | | |
| 23 | LL | f(); | |
| 24 | | ^-- argument #1 of type `(dyn Fn() + 'static)` is missing | |
| 25 | | | |
| 26 | note: closure defined here | |
| 27 | --> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:13 | |
| 28 | | | |
| 29 | LL | let f = |f: dyn Fn()| f; | |
| 30 | | ^^^^^^^^^^^^^ | |
| 31 | help: provide the argument | |
| 32 | | | |
| 33 | LL | f(/* (dyn Fn() + 'static) */); | |
| 34 | | ++++++++++++++++++++++++++ | |
| 35 | ||
| 36 | error: aborting due to 3 previous errors | |
| 37 | ||
| 38 | Some errors have detailed explanations: E0057, E0277, E0746. | |
| 39 | For more information about an error, try `rustc --explain E0057`. |