authorbors <bors@rust-lang.org> 2026-06-30 05:19:16 UTC
committerbors <bors@rust-lang.org> 2026-06-30 05:19:16 UTC
log345632878cffcb4c8e90750e943296b43d16c76e
tree39a30c218913b717d5e4ea4e80c0d7abb6f83577
parent096694416a41840709140eb0fd0ca193d1a3e6ba
parent977911031effd4c53f0903406fa657c56bef4184

Auto merge of #158593 - JonathanBrouwer:rollup-tGO5Zmu, r=JonathanBrouwer

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};
5555use rustc_span::symbol::kw;
5656use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
5757
58use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
58use crate::delegation::generics::{
59 GenericsGenerationResult, GenericsGenerationResults, GenericsPosition,
60};
5961use crate::diagnostics::{
6062 CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion,
6163 DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee,
......@@ -505,6 +507,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
505507 res: Res::Local(param_id),
506508 args: None,
507509 infer_args: false,
510 delegation_child_segment: false,
508511 }));
509512
510513 let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments });
......@@ -714,6 +717,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
714717 result.args_segment_id = segment.hir_id;
715718 result.use_for_sig_inheritance = !result.generics.is_trait_impl();
716719
720 segment.delegation_child_segment = result.generics.pos() == GenericsPosition::Child;
721
717722 segment
718723 }
719724
compiler/rustc_ast_lowering/src/delegation/generics.rs+10-2
......@@ -12,7 +12,7 @@ use rustc_span::{Ident, Span, sym};
1212use crate::LoweringContext;
1313use crate::diagnostics::DelegationInfersMismatch;
1414
15#[derive(Debug, Clone, Copy)]
15#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1616pub(super) enum GenericsPosition {
1717 Parent,
1818 Child,
......@@ -155,7 +155,7 @@ impl<'hir> DelegationGenericArgsIterator<'hir> {
155155impl<'hir> HirOrTyGenerics<'hir> {
156156 pub(super) fn into_hir_generics(&mut self, ctx: &mut LoweringContext<'_, 'hir>, span: Span) {
157157 if let HirOrTyGenerics::Ty(ty) = self {
158 let rename_self = matches!(ty.pos, GenericsPosition::Child);
158 let rename_self = ty.pos == GenericsPosition::Child;
159159 let params = ctx.uplift_delegation_generic_params(span, &ty.data, rename_self);
160160
161161 *self = HirOrTyGenerics::Hir(DelegationGenerics {
......@@ -218,6 +218,13 @@ impl<'hir> HirOrTyGenerics<'hir> {
218218 .expect("`Self` generic param is not found while expected"),
219219 }
220220 }
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 }
221228}
222229
223230impl<'hir> GenericsGenerationResult<'hir> {
......@@ -590,6 +597,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
590597 ident: p.name.ident(),
591598 infer_args: false,
592599 res,
600 delegation_child_segment: false,
593601 }]),
594602 res,
595603 span: p.span,
compiler/rustc_ast_lowering/src/lib.rs+2-1
......@@ -1014,6 +1014,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
10141014 res,
10151015 args,
10161016 infer_args: args.is_none(),
1017 delegation_child_segment: false,
10171018 }]),
10181019 })
10191020 }
......@@ -2791,7 +2792,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
27912792 }
27922793 ExprKind::ConstBlock(anon_const) => {
27932794 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));
27952796 self.lower_anon_const_to_const_arg(anon_const, span)
27962797 }
27972798 _ => overly_complex_const(self),
compiler/rustc_ast_lowering/src/path.rs+1
......@@ -412,6 +412,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
412412 } else {
413413 Some(generic_args.into_generic_args(self))
414414 },
415 delegation_child_segment: false,
415416 }
416417 }
417418
compiler/rustc_borrowck/src/universal_regions.rs+1-1
......@@ -615,7 +615,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
615615
616616 BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
617617 match tcx.def_kind(self.mir_def) {
618 DefKind::InlineConst => {
618 DefKind::InlineConst if !tcx.is_type_system_inline_const(self.mir_def) => {
619619 // This is required for `AscribeUserType` canonical query, which will call
620620 // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes
621621 // 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};
22use rustc_abi::Primitive::Pointer;
33use rustc_abi::{self as abi, HasDataLayout};
44use rustc_codegen_ssa::traits::{
5 BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
5 BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, PacMetadata,
6 StaticCodegenMethods,
67};
78use rustc_middle::mir::Mutability;
89use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
......@@ -241,7 +242,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
241242 None
242243 }
243244
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> {
245252 let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
246253 match cv {
247254 Scalar::Int(int) => {
......@@ -290,7 +297,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
290297 }
291298 value
292299 }
293 GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
300 GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, None),
294301 GlobalAlloc::VTable(ty, dyn_ty) => {
295302 let alloc = self
296303 .tcx
compiler/rustc_codegen_gcc/src/context.rs+4-2
......@@ -5,7 +5,9 @@ use gccjit::{Block, CType, Context, Function, FunctionType, LValue, Location, RV
55use rustc_abi::{Align, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
66use rustc_codegen_ssa::base::wants_msvc_seh;
77use rustc_codegen_ssa::errors as ssa_errors;
8use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods};
8use rustc_codegen_ssa::traits::{
9 BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods, PacMetadata,
10};
911use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
1012use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1113use rustc_middle::mir::interpret::Allocation;
......@@ -398,7 +400,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
398400 get_fn(self, instance)
399401 }
400402
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> {
402404 let func_name = self.tcx.symbol_name(instance).name;
403405
404406 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::{
1212};
1313use rustc_span::sym;
1414use rustc_symbol_mangling::mangle_internal_symbol;
15use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector};
15use rustc_target::spec::{
16 Arch, FramePointer, LlvmAbi, SanitizerSet, StackProbeType, StackProtector,
17};
1618use smallvec::SmallVec;
1719
20use crate::common::pauth_fn_attrs;
1821use crate::context::SimpleCx;
1922use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte};
2023use crate::llvm::AttributePlace::Function;
......@@ -643,6 +646,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
643646 }
644647 }
645648
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
646655 to_add.extend(target_features_attr(cx, tcx, function_features));
647656
648657 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;
2525use rustc_middle::ty::TyCtxt;
2626use rustc_session::config::{DebugInfo, Offload};
2727use rustc_span::Symbol;
28use rustc_target::spec::SanitizerSet;
28use rustc_target::spec::{LlvmAbi, SanitizerSet};
2929
3030use super::ModuleLlvm;
3131use crate::attributes;
3232use crate::builder::Builder;
3333use crate::builder::gpu_offload::OffloadGlobals;
34use crate::common::pauth_fn_attrs;
3435use crate::context::CodegenCx;
3536use crate::llvm::{self, Value};
3637
......@@ -123,7 +124,18 @@ pub(crate) fn compile_codegen_unit(
123124 if let Some(entry) =
124125 maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit)
125126 {
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 }
127139 attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
128140 }
129141
......@@ -140,6 +152,30 @@ pub(crate) fn compile_codegen_unit(
140152 cx.add_objc_module_flags();
141153 }
142154
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
143179 // Finalize code coverage by injecting the coverage map. Note, the coverage map will
144180 // also be added to the `llvm.compiler.used` variable, created next.
145181 if cx.sess().instrument_coverage() {
compiler/rustc_codegen_llvm/src/builder.rs+51-2
......@@ -7,7 +7,7 @@ pub(crate) mod autodiff;
77pub(crate) mod gpu_offload;
88
99use libc::{c_char, c_uint};
10use rustc_abi::{self as abi, Align, Size, WrappingRange};
10use rustc_abi::{self as abi, Align, CanonAbi, Size, WrappingRange};
1111use rustc_codegen_ssa::MemFlags;
1212use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
1313use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
......@@ -26,7 +26,7 @@ use rustc_sanitizers::{cfi, kcfi};
2626use rustc_session::config::OptLevel;
2727use rustc_span::Span;
2828use rustc_target::callconv::{FnAbi, PassMode};
29use rustc_target::spec::{Arch, HasTargetSpec, SanitizerSet, Target};
29use rustc_target::spec::{Arch, HasTargetSpec, LlvmAbi, SanitizerSet, Target};
3030use smallvec::SmallVec;
3131use tracing::{debug, instrument};
3232
......@@ -475,6 +475,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
475475 bundles.push(kcfi_bundle);
476476 }
477477
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
478483 let invoke = unsafe {
479484 llvm::LLVMBuildInvokeWithOperandBundles(
480485 self.llbuilder,
......@@ -1472,6 +1477,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
14721477 bundles.push(kcfi_bundle);
14731478 }
14741479
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
14751485 let call = unsafe {
14761486 llvm::LLVMBuildCallWithOperandBundles(
14771487 self.llbuilder,
......@@ -1902,6 +1912,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
19021912 bundles.push(kcfi_bundle);
19031913 }
19041914
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
19051920 let callbr = unsafe {
19061921 llvm::LLVMBuildCallBr(
19071922 self.llbuilder,
......@@ -2021,6 +2036,40 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
20212036 kcfi_bundle
20222037 }
20232038
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
20242073 /// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation.
20252074 #[instrument(level = "debug", skip(self))]
20262075 pub(crate) fn instrprof_increment(
compiler/rustc_codegen_llvm/src/common.rs+82-9
......@@ -4,23 +4,81 @@ use std::borrow::Borrow;
44
55use libc::{c_char, c_uint};
66use rustc_abi::Primitive::Pointer;
7use rustc_abi::{self as abi, HasDataLayout as _};
7use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _};
88use rustc_ast::Mutability;
99use rustc_codegen_ssa::common::TypeKind;
1010use rustc_codegen_ssa::traits::*;
1111use rustc_data_structures::stable_hash::{StableHash, StableHasher};
1212use rustc_hashes::Hash128;
13use rustc_hir::def::DefKind;
1314use rustc_hir::def_id::DefId;
1415use rustc_middle::bug;
1516use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
16use rustc_middle::ty::TyCtxt;
17use rustc_middle::ty::{Instance, TyCtxt};
1718use rustc_session::cstore::DllImport;
19use rustc_target::spec::LlvmAbi;
1820use tracing::debug;
1921
20use crate::consts::const_alloc_to_llvm;
22use crate::consts::{IsInitOrFini, IsStatic, const_alloc_to_llvm};
2123pub(crate) use crate::context::CodegenCx;
2224use crate::context::{GenericCx, SCx};
23use crate::llvm::{self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value};
25use crate::llvm::{
26 self, BasicBlock, ConstantInt, FALSE, TRUE, ToLlvmBool, Type, Value, const_ptr_auth,
27};
28
29#[inline]
30pub(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
43pub(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}
2482
2583/*
2684* A note on nomenclature of linking: "extern", "foreign", and "upcall".
......@@ -268,7 +326,13 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
268326 })
269327 }
270328
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 {
272336 let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
273337 match cv {
274338 Scalar::Int(int) => {
......@@ -297,8 +361,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
297361 self.const_bitcast(llval, llty)
298362 };
299363 } 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 );
302370 let alloc = alloc.inner();
303371 let value = match alloc.mutability {
304372 Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
......@@ -319,7 +387,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
319387 value
320388 }
321389 }
322 GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance),
390 GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance, pac),
323391 GlobalAlloc::VTable(ty, dyn_ty) => {
324392 let alloc = self
325393 .tcx
......@@ -330,7 +398,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
330398 }),
331399 )))
332400 .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 );
334407 self.static_addr_of_impl(init, alloc.inner().align, None)
335408 }
336409 GlobalAlloc::Static(def_id) => {
compiler/rustc_codegen_llvm/src/consts.rs+76-11
......@@ -1,6 +1,6 @@
11use std::ops::Range;
22
3use rustc_abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
3use rustc_abi::{Align, ExternAbi, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
44use rustc_codegen_ssa::common;
55use rustc_codegen_ssa::traits::*;
66use rustc_hir::LangItem;
......@@ -17,19 +17,30 @@ use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
1717use rustc_middle::ty::{self, Instance};
1818use rustc_middle::{bug, span_bug};
1919use rustc_span::Symbol;
20use rustc_target::spec::Arch;
20use rustc_target::spec::{Arch, LlvmAbi};
2121use tracing::{debug, instrument, trace};
2222
2323use crate::common::CodegenCx;
2424use crate::errors::SymbolAlreadyDefined;
25use crate::llvm::{self, Type, Value};
25use crate::llvm::{self, Type, Value, const_ptr_auth};
2626use crate::type_of::LayoutLlvmExt;
2727use crate::{base, debuginfo};
2828
29/// Indicates whether a value originates from a `static`.
30pub(crate) enum IsStatic {
31 Yes,
32 No,
33}
34/// Indicates whether a symbol is part of `.init_array` or `.fini_array`.
35pub(crate) enum IsInitOrFini {
36 Yes,
37 No,
38}
2939pub(crate) fn const_alloc_to_llvm<'ll>(
3040 cx: &CodegenCx<'ll, '_>,
3141 alloc: &Allocation,
32 is_static: bool,
42 is_static: IsStatic,
43 is_init_fini: IsInitOrFini,
3344) -> &'ll Value {
3445 // We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or
3546 // 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>(
3849 //
3950 // Statics have a guaranteed meaningful address so it's less clear that we want to do
4051 // something like this; it's also harder.
41 if !is_static {
52 if matches!(is_static, IsStatic::No) {
4253 assert!(alloc.len() != 0);
4354 }
4455 let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1);
......@@ -109,14 +120,31 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
109120 as u64;
110121
111122 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(
114141 InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx),
115142 Scalar::Initialized {
116143 value: Primitive::Pointer(address_space),
117144 valid_range: WrappingRange::full(pointer_size),
118145 },
119146 cx.type_ptr_ext(address_space),
147 pac_metadata,
120148 ));
121149 next_offset = offset + pointer_size_bytes;
122150 }
......@@ -141,7 +169,21 @@ fn codegen_static_initializer<'ll, 'tcx>(
141169 def_id: DefId,
142170) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
143171 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))
145187}
146188
147189fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) {
......@@ -164,6 +206,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
164206 if let Some(linkage) = attrs.import_linkage {
165207 debug!("get_static: sym={} linkage={:?}", sym, linkage);
166208
209 let mut should_sign = false;
167210 // Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare
168211 // an extern_weak function, otherwise a global with the desired linkage.
169212 let g1 = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) {
......@@ -176,8 +219,13 @@ fn check_and_apply_linkage<'ll, 'tcx>(
176219 && let ty::FnPtr(sig, header) = args.type_at(0).kind()
177220 {
178221 let fn_sig = sig.with(*header);
179
180222 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 }
181229 cx.declare_fn(sym, &fn_abi, None)
182230 } else {
183231 cx.declare_global(sym, cx.type_i8())
......@@ -207,7 +255,24 @@ fn check_and_apply_linkage<'ll, 'tcx>(
207255 });
208256 llvm::set_linkage(g2, llvm::Linkage::InternalLinkage);
209257 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
211276 g2
212277 } else if cx.tcx.sess.target.arch == Arch::X86
213278 && common::is_mingw_gnu_toolchain(&cx.tcx.sess.target)
......@@ -776,7 +841,7 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> {
776841 fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value {
777842 // FIXME: should we cache `const_alloc_to_llvm` to avoid repeating this for the
778843 // 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);
780845
781846 let gv = self.static_addr_of_impl(cv, alloc.inner().align, kind);
782847 // 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> {
727727 }
728728 }
729729
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
730748 // We do our best here to match what Clang does when compiling Objective-C natively.
731749 // See Clang's `CGObjCCommonMac::EmitImageInfo`:
732750 // 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> {
871889 get_fn(self, instance)
872890 }
873891
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 }
876910 }
877911
878912 fn eh_personality(&self) -> &'ll Value {
......@@ -914,13 +948,16 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
914948
915949 let tcx = self.tcx;
916950 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 ),
924961 _ => {
925962 let name = name.unwrap_or("rust_eh_personality");
926963 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;
2828use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
2929use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
3030use rustc_target::callconv::PassMode;
31use rustc_target::spec::Arch;
31use rustc_target::spec::{Arch, LlvmAbi};
3232use tracing::debug;
3333
3434use crate::abi::FnAbiLlvmExt;
......@@ -37,6 +37,7 @@ use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
3737use crate::builder::gpu_offload::{
3838 OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload,
3939};
40use crate::common::pauth_fn_attrs;
4041use crate::context::CodegenCx;
4142use crate::declare::declare_raw_fn;
4243use crate::errors::{
......@@ -44,7 +45,7 @@ use crate::errors::{
4445 OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic,
4546};
4647use crate::intrinsic::ty::typetree::fnc_typetrees;
47use crate::llvm::{self, Type, Value};
48use crate::llvm::{self, Attribute, AttributePlace, Type, Value};
4849use crate::type_of::LayoutLlvmExt;
4950use crate::va_arg::emit_va_arg;
5051
......@@ -1711,6 +1712,13 @@ fn get_rust_try_fn<'a, 'll, 'tcx>(
17111712 hir::Safety::Unsafe,
17121713 ));
17131714 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
17141722 cx.rust_try_fn.set(Some(rust_try));
17151723 rust_try
17161724}
compiler/rustc_codegen_llvm/src/llvm/ffi.rs+8
......@@ -2647,4 +2647,12 @@ unsafe extern "C" {
26472647 Aliasee: &Value,
26482648 Name: *const c_char,
26492649 ) -> &'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;
26502658}
compiler/rustc_codegen_llvm/src/llvm/mod.rs+16
......@@ -475,3 +475,19 @@ pub(crate) fn add_alias<'ll>(
475475) -> &'ll Value {
476476 unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) }
477477}
478
479/// Safe wrapper for `LLVMRustConstPtrAuth`.
480pub(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>>(
493493 return None;
494494 }
495495
496 let main_llfn = cx.get_fn_addr(instance);
496 let main_llfn = cx.get_fn_addr(instance, Some(PacMetadata::default()));
497497
498498 let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
499499 return Some(entry_fn);
......@@ -554,7 +554,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
554554 cx.tcx().mk_args(&[main_ret_ty.into()]),
555555 DUMMY_SP,
556556 );
557 let start_fn = cx.get_fn_addr(start_instance);
557 let start_fn = cx.get_fn_addr(start_instance, Some(PacMetadata::default()));
558558
559559 let i8_ty = cx.type_i8();
560560 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>>(
117117 let tcx = bx.tcx();
118118 let def_id = tcx.require_lang_item(li, span);
119119 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 )
121125}
122126
123127pub(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> {
686686 }
687687 _ => (
688688 false,
689 bx.get_fn_addr(drop_fn),
689 bx.get_fn_addr(drop_fn, Some(PacMetadata::default())),
690690 bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
691691 drop_fn,
692692 ),
......@@ -1097,7 +1097,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10971097 )
10981098 .unwrap();
10991099
1100 (None, Some(bx.get_fn_addr(instance)))
1100 (None, Some(bx.get_fn_addr(instance, Some(PacMetadata::default()))))
11011101 }
11021102 _ => (Some(instance), None),
11031103 }
......@@ -1410,7 +1410,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14101410 }
14111411
14121412 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())),
14141414 (_, Some(llfn)) => llfn,
14151415 _ => span_bug!(fn_span, "no instance or llfn for call"),
14161416 };
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> {
434434 args,
435435 )
436436 .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 )
438443 }
439444 _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
440445 }
......@@ -448,7 +453,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
448453 args,
449454 ty::ClosureKind::FnOnce,
450455 );
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 )
452462 }
453463 _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
454464 }
......@@ -668,7 +678,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
668678 def: ty::InstanceKind::Shim(ty::ShimKind::ThreadLocal(def_id)),
669679 args: ty::GenericArgs::empty(),
670680 };
671 let fn_ptr = bx.get_fn_addr(instance);
681 let fn_ptr = bx.get_fn_addr(instance, Some(PacMetadata::default()));
672682 let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
673683 let fn_ty = bx.fn_decl_backend_type(fn_abi);
674684 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;
22use rustc_middle::mir::interpret::Scalar;
33
44use super::BackendTypes;
5use crate::traits::PacMetadata;
56
67pub trait ConstCodegenMethods: BackendTypes {
78 // Constant constructors
......@@ -38,7 +39,16 @@ pub trait ConstCodegenMethods: BackendTypes {
3839 fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
3940 fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
4041
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;
4252
4353 fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value;
4454}
compiler/rustc_codegen_ssa/src/traits/misc.rs+30-1
......@@ -7,6 +7,35 @@ use rustc_span::Symbol;
77
88use super::BackendTypes;
99
10/// Strategy for incorporating address-based diversity into PAC computation.
11#[derive(Default)]
12pub 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.
24pub 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
33impl Default for PacMetadata {
34 fn default() -> Self {
35 PacMetadata { key: 0, disc: 0, addr_diversity: AddressDiversity::default() }
36 }
37}
38
1039pub trait MiscCodegenMethods<'tcx>: BackendTypes {
1140 fn vtables(
1241 &self,
......@@ -19,7 +48,7 @@ pub trait MiscCodegenMethods<'tcx>: BackendTypes {
1948 ) {
2049 }
2150 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;
2352 fn eh_personality(&self) -> Self::Function;
2453 fn sess(&self) -> &Session;
2554 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;
4242pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoCodegenMethods};
4343pub use self::declare::PreDefineCodegenMethods;
4444pub use self::intrinsic::IntrinsicCallBuilderMethods;
45pub use self::misc::MiscCodegenMethods;
45pub use self::misc::{AddressDiversity, MiscCodegenMethods, PacMetadata};
4646pub use self::statics::{StaticBuilderMethods, StaticCodegenMethods};
4747pub use self::type_::{
4848 ArgAbiBuilderMethods, BaseTypeCodegenMethods, DerivedTypeCodegenMethods,
compiler/rustc_hir/src/def.rs-37
......@@ -448,43 +448,6 @@ impl DefKind {
448448 | DefKind::ExternCrate => false,
449449 }
450450 }
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 }
488451}
489452
490453/// The resolution of a path or export.
compiler/rustc_hir/src/hir.rs+13-1
......@@ -387,12 +387,24 @@ pub struct PathSegment<'hir> {
387387 /// out of those only the segments with no type parameters
388388 /// to begin with, e.g., `Vec::new` is `<Vec<..>>::new::<..>`.
389389 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,
390395}
391396
392397impl<'hir> PathSegment<'hir> {
393398 /// Converts an identifier to the corresponding segment.
394399 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 }
396408 }
397409
398410 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>>(
14681468 visitor: &mut V,
14691469 segment: &'v PathSegment<'v>,
14701470) -> 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;
14721473 try_visit!(visitor.visit_ident(*ident));
14731474 try_visit!(visitor.visit_id(*hir_id));
14741475 visit_opt!(visitor, visit_generic_args, *args);
compiler/rustc_hir_analysis/src/collect.rs+4-2
......@@ -15,7 +15,7 @@
1515//! crate as a kind of pass. This should eventually be factored away.
1616
1717use std::cell::Cell;
18use std::{assert_matches, iter};
18use std::{assert_matches, debug_assert_matches, iter};
1919
2020use rustc_abi::{ExternAbi, Size};
2121use rustc_ast::Recovered;
......@@ -1635,10 +1635,12 @@ fn const_param_default<'tcx>(
16351635}
16361636
16371637fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind {
1638 debug_assert_matches!(tcx.def_kind(def), DefKind::AnonConst | DefKind::InlineConst);
16381639 let hir_id = tcx.local_def_id_to_hir_id(def);
16391640 let const_arg_id = tcx.parent_hir_id(hir_id);
16401641 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);
16421644 let parent_hir_node = tcx.hir_node(tcx.parent_hir_id(const_arg_id));
16431645 if tcx.features().generic_const_exprs() {
16441646 ty::AnonConstKind::GCE
compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs+1
......@@ -467,6 +467,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
467467 res: Res::Err,
468468 args: Some(constraint.gen_args),
469469 infer_args: false,
470 delegation_child_segment: false,
470471 };
471472
472473 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> + '_ {
471471 res: Res::Err,
472472 args: Some(constraint.gen_args),
473473 infer_args: false,
474 delegation_child_segment: false,
474475 };
475476
476477 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(
434434
435435 // Suppress this warning for delegations as it is compiler generated and lifetimes are
436436 // 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 {
438438 true => ExplicitLateBound::No,
439439 false => prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos),
440440 };
compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs+5-9
......@@ -483,7 +483,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
483483 let tcx = self.tcx();
484484 let parent_def_id = self.item_def_id();
485485 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)
487487 && let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id)
488488 {
489489 let folder = ForbidParamUsesFolder {
......@@ -512,15 +512,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
512512 // Inline consts and closures can be nested inside anon consts that forbid generic
513513 // params (e.g. an enum discriminant). Walk up the def parent chain to find the
514514 // 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
515517 let anon_const_def_id = match tcx.def_kind(parent_def_id) {
516518 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,
524520 _ => return None,
525521 };
526522
......@@ -870,7 +866,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
870866 span,
871867 generic_args: segment.args(),
872868 infer_args: segment.infer_args,
873 create_synth_args: tcx.hir_is_delegation_child_segment(segment),
869 create_synth_args: segment.delegation_child_segment,
874870 incorrect_args: &arg_count.correct,
875871 };
876872
compiler/rustc_hir_analysis/src/lib.rs+6-2
......@@ -186,9 +186,13 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
186186 }
187187 _ => (),
188188 }
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`.
190191 // 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 {
192196 tcx.ensure_ok().typeck(item_def_id);
193197 }
194198 // 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};
99use rustc_hir_analysis::autoderef::Autoderef;
1010use rustc_infer::infer::BoundRegionConversionTime;
1111use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
12use rustc_middle::bug;
1213use rustc_middle::ty::adjustment::{
1314 Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
1415};
1516use rustc_middle::ty::{self, FnSig, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
16use rustc_middle::{bug, span_bug};
1717use rustc_span::def_id::LocalDefId;
1818use rustc_span::{Ident, Span, sym};
1919use rustc_target::spec::{AbiMap, AbiMapping};
......@@ -1186,11 +1186,16 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
11861186 );
11871187 }
11881188 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));
11941199 }
11951200 }
11961201 }
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
8484 CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() };
8585 let cx = match tcx.def_kind(def_id) {
8686 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 }
8792 _ => Fn,
8893 };
8994 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,
288288 // Just print a bare list of target CPU names, and let Rust-side code handle
289289 // the full formatting of `--print=target-cpus`.
290290 for (auto &CPU : CPUTable) {
291#if LLVM_VERSION_GE(23, 0)
292 OS << CPU.key() << "\n";
293#else
291294 OS << CPU.Key << "\n";
295#endif
292296 }
293297}
294298
......@@ -315,9 +319,15 @@ extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index,
315319#endif
316320 const ArrayRef<SubtargetFeatureKV> FeatTable =
317321 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
318327 const SubtargetFeatureKV Feat = FeatTable[Index];
319328 *Feature = Feat.Key;
320329 *Desc = Feat.Desc;
330#endif
321331}
322332
323333extern "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) {
18481848 return Intrinsic::isTargetIntrinsic(ID);
18491849}
18501850
1851extern "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
18511880// Statically assert that the fixed metadata kind IDs declared in
18521881// `metadata_kind.rs` match the ones actually used by LLVM.
18531882#define FIXED_MD_KIND(VARIANT, VALUE) \
compiler/rustc_metadata/src/diagnostics.rs+15
......@@ -704,3 +704,18 @@ pub(crate) struct MitigationLessStrictInDependency {
704704 pub mitigation_level: String,
705705 pub extern_crate: Symbol,
706706}
707
708#[derive(Diagnostic)]
709pub(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>
197197 }
198198 }
199199 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 }
200225 collector.libs
201226}
202227
compiler/rustc_metadata/src/rmeta/encoder.rs+1-1
......@@ -1624,7 +1624,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16241624 <- tcx.explicit_implied_const_bounds(def_id).skip_binder());
16251625 }
16261626 }
1627 if let DefKind::AnonConst = def_kind {
1627 if let DefKind::AnonConst | DefKind::InlineConst = def_kind {
16281628 record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
16291629 }
16301630 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};
2222use crate::hir::{ModuleItems, ProjectedMaybeOwner, nested_filter};
2323use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
2424use crate::query::{IntoQueryKey, LocalCrate};
25use crate::ty::TyCtxt;
25use crate::ty::{self, TyCtxt};
2626
2727/// An iterator that walks up the ancestor tree of a given `HirId`.
2828/// Constructed using `tcx.hir_parent_iter(hir_id)`.
......@@ -879,13 +879,6 @@ impl<'tcx> TyCtxt<'tcx> {
879879 self.hir_opt_delegation_info(delegation_id).expect("processing delegation")
880880 }
881881
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
889882 #[inline]
890883 fn hir_opt_ident(self, id: HirId) -> Option<Ident> {
891884 match self.hir_node(id) {
......@@ -1115,6 +1108,12 @@ impl<'tcx> TyCtxt<'tcx> {
11151108 }
11161109 }
11171110
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
11181117 pub fn hir_maybe_get_struct_pattern_shorthand_field(self, expr: &Expr<'_>) -> Option<Symbol> {
11191118 let local = match expr {
11201119 Expr {
compiler/rustc_middle/src/ty/context.rs+8-1
......@@ -601,7 +601,14 @@ impl<'tcx> TyCtxt<'tcx> {
601601 /// effect. However, we do not want this as a general capability, so this interface restricts
602602 /// to the only allowed case.
603603 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
605612 TyCtxtFeed { tcx: self, key }.type_of(value)
606613 }
607614
compiler/rustc_middle/src/ty/context/impl_interner.rs+4-3
......@@ -244,7 +244,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
244244 DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy { def_id },
245245 DefKind::TyAlias => ty::AliasTermKind::FreeTy { def_id },
246246 DefKind::Const { .. } => ty::AliasTermKind::FreeConst { def_id },
247 DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => {
247 DefKind::AnonConst | DefKind::InlineConst | DefKind::Ctor(_, CtorKind::Const) => {
248248 ty::AliasTermKind::AnonConst { def_id }
249249 }
250250 kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
......@@ -541,8 +541,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
541541 // only want to consider types that *actually* unify with float/int vars.
542542 fn for_each_relevant_impl<R: VisitorResult>(
543543 self,
544 trait_def_id: DefId,
545 self_ty: Ty<'tcx>,
544 trait_ref: ty::TraitRef<'tcx>,
546545 mut f: impl FnMut(DefId) -> R,
547546 ) -> R {
548547 macro_rules! ret {
......@@ -554,6 +553,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
554553 };
555554 }
556555
556 let trait_def_id = trait_ref.def_id;
557 let self_ty = trait_ref.self_ty();
557558 let tcx = self;
558559 let trait_impls = tcx.trait_impls_of(trait_def_id);
559560 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> {
597597 /// Returns `true` if `def_id` refers to a definition that does not have its own
598598 /// type-checking context, i.e. closure, coroutine or inline const.
599599 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 }
601632 }
602633
603634 /// 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
5252 F: FnOnce() -> B,
5353 B: Deref<Target = Body<'tcx>>,
5454{
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,
6059 }
6160
6261 // 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
539539 candidates: &mut Vec<Candidate<I>>,
540540 ) -> Result<(), RerunNonErased> {
541541 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 }
560557
561 Ok(())
562 },
563 )
558 Ok(())
559 })
564560 }
565561
566562 #[instrument(level = "trace", skip_all)]
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+3-7
......@@ -1246,13 +1246,9 @@ where
12461246 let self_ty = goal.predicate.self_ty();
12471247 let check_impls = || {
12481248 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 });
12561252 if let Some(def_id) = disqualifying_impl {
12571253 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
12581254 // 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};
1717
1818use crate::macros::MacroRulesScopeRef;
1919use crate::{
20 ConstArgContext, ImplTraitContext, InvocationParent, ParentScope, Resolver, with_owner,
21 with_owner_tables,
20 ImplTraitContext, InvocationParent, ParentScope, Resolver, with_owner, with_owner_tables,
2221};
2322
2423pub(crate) fn collect_definitions<'ra>(
......@@ -115,12 +114,6 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
115114 self.invocation_parent.impl_trait_context = orig_itc;
116115 }
117116
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
124117 fn collect_field(&mut self, field: &'a FieldDef, index: Option<usize>) {
125118 let index = |this: &Self| {
126119 index.unwrap_or_else(|| {
......@@ -430,6 +423,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
430423 }
431424
432425 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
433429 // `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so
434430 // to avoid affecting stable we have to feature gate the not creating
435431 // anon consts
......@@ -441,16 +437,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
441437 }
442438
443439 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),
447441 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));
454446 }
455447 };
456448 }
......@@ -459,60 +451,28 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
459451 fn visit_expr(&mut self, expr: &'a Expr) {
460452 debug!(?self.invocation_parent);
461453
462 let parent_def = match &expr.kind {
454 match &expr.kind {
463455 ExprKind::MacCall(..) => {
464456 self.visit_macro_invoc(expr.id);
465457 self.visit_invoc(expr.id);
466 return;
467458 }
468459 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));
470462 }
471463 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);
505466 }
506 },
507467
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 }
516476 }
517477
518478 fn visit_ty(&mut self, ty: &'a Ty) {
compiler/rustc_resolve/src/lib.rs-9
......@@ -187,7 +187,6 @@ struct InvocationParent {
187187 parent_def: LocalDefId,
188188 impl_trait_context: ImplTraitContext,
189189 in_attr: bool,
190 const_arg_context: ConstArgContext,
191190 owner: NodeId,
192191}
193192
......@@ -196,7 +195,6 @@ impl InvocationParent {
196195 parent_def: CRATE_DEF_ID,
197196 impl_trait_context: ImplTraitContext::Existential,
198197 in_attr: false,
199 const_arg_context: ConstArgContext::NonDirect,
200198 owner: CRATE_NODE_ID,
201199 };
202200}
......@@ -208,13 +206,6 @@ enum ImplTraitContext {
208206 InBinding,
209207}
210208
211#[derive(Copy, Clone, Debug)]
212enum ConstArgContext {
213 Direct,
214 /// Either inside of an `AnonConst` or not inside a const argument at all.
215 NonDirect,
216}
217
218209/// Used for tracking import use types which will be used for redundant import checking.
219210///
220211/// ### Used::Scope Example
compiler/rustc_session/src/errors.rs+6
......@@ -311,6 +311,12 @@ pub(crate) struct CannotMixAndMatchSanitizers {
311311)]
312312pub(crate) struct CannotEnableCrtStaticLinux;
313313
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)]
318pub(crate) struct CannotEnableCrtStaticPointerAuth;
319
314320#[derive(Diagnostic)]
315321#[diag("`-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`")]
316322pub(crate) struct SanitizerCfiRequiresLto;
compiler/rustc_session/src/options.rs+1
......@@ -2650,6 +2650,7 @@ options! {
26502650 "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
26512651 profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
26522652 "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"),
26532654 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
26542655 "enable queries of the dependency graph for regression testing (default: no)"),
26552656 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};
2929use rustc_span::{RealFileName, Span, Symbol};
3030use rustc_target::asm::InlineAsmArch;
3131use 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,
3535};
3636
3737use crate::code_stats::CodeStats;
......@@ -1229,6 +1229,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
12291229 sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
12301230 }
12311231
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
12321239 // LLVM CFI requires LTO.
12331240 if sess.is_sanitizer_cfi_enabled()
12341241 && !(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! {
14881488 ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
14891489 ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
14901490 ("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl),
1491 ("aarch64-unknown-linux-pauthtest", aarch64_unknown_linux_pauthtest),
14911492 ("aarch64_be-unknown-linux-musl", aarch64_be_unknown_linux_musl),
14921493 ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
14931494 ("i686-unknown-linux-musl", i686_unknown_linux_musl),
......@@ -2072,6 +2073,7 @@ crate::target_spec_enum! {
20722073 Ilp32e = "ilp32e",
20732074 Llvm = "llvm",
20742075 MacAbi = "macabi",
2076 Pauthtest = "pauthtest",
20752077 Sim = "sim",
20762078 SoftFloat = "softfloat",
20772079 Spe = "spe",
......@@ -2112,6 +2114,8 @@ crate::target_spec_enum! {
21122114 // PowerPC
21132115 ElfV1 = "elfv1",
21142116 ElfV2 = "elfv2",
2117 // Pointer authentication: Pauthtest
2118 Pauthtest = "pauthtest",
21152119
21162120 Unspecified = "",
21172121 }
......@@ -3398,9 +3402,10 @@ impl Target {
33983402 )
33993403 }
34003404 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"
34043409 );
34053410 check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on aarch64");
34063411 // FIXME: Ensure that target_abi = "ilp32" correlates with actually using that ABI.
......@@ -3413,6 +3418,7 @@ impl Target {
34133418 CfgAbi::Ilp32
34143419 | CfgAbi::Llvm
34153420 | CfgAbi::MacAbi
3421 | CfgAbi::Pauthtest
34163422 | CfgAbi::Sim
34173423 | CfgAbi::Uwp
34183424 | CfgAbi::Unspecified
compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_pauthtest.rs created+38
......@@ -0,0 +1,38 @@
1use crate::spec::{
2 Arch, CfgAbi, Env, FramePointer, LinkSelfContainedDefault, LlvmAbi, StackProbeType, Target,
3 TargetMetadata, TargetOptions, base,
4};
5
6pub(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> {
25562556 err.children.clear();
25572557
25582558 let mut span = obligation.cause.span;
2559 let mut is_async_fn_return = false;
25592560 if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id)
25602561 && let parent = self.tcx.local_parent(obligation.cause.body_id)
25612562 && let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent)
......@@ -2571,10 +2572,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
25712572 // and
25722573 // async fn foo() -> dyn Display Box<dyn { .. }>
25732574 span = fn_sig.decl.output.span();
2575 is_async_fn_return = true;
25742576 err.span(span);
25752577 }
25762578 let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);
25772579
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
25782588 let mut visitor = ReturnsVisitor::default();
25792589 visitor.visit_body(&body);
25802590
compiler/rustc_ty_utils/src/opaque_types.rs+9-8
......@@ -317,6 +317,10 @@ fn opaque_types_defined_by<'tcx>(
317317 tcx: TyCtxt<'tcx>,
318318 item: LocalDefId,
319319) -> &'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.
320324 if tcx.is_typeck_child(item.to_def_id()) {
321325 return tcx.opaque_types_defined_by(tcx.local_parent(item));
322326 }
......@@ -332,7 +336,11 @@ fn opaque_types_defined_by<'tcx>(
332336 | DefKind::Static { .. }
333337 | DefKind::Const { .. }
334338 | 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
336344 collector.collect_taits_declared_in_body();
337345 }
338346 DefKind::AssocTy | DefKind::TyAlias | DefKind::GlobalAsm => {}
......@@ -345,15 +353,8 @@ fn opaque_types_defined_by<'tcx>(
345353 | DefKind::Trait
346354 | DefKind::ForeignTy
347355 | 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.
353356 | DefKind::Closure
354 | DefKind::InlineConst
355357 | DefKind::SyntheticCoroutineBody
356
357358 | DefKind::TyParam
358359 | DefKind::ConstParam
359360 | DefKind::Ctor(_, _)
compiler/rustc_ty_utils/src/sig_types.rs+20-18
......@@ -21,6 +21,24 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
2121) -> V::Result {
2222 let kind = tcx.def_kind(item);
2323 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 };
2442 match kind {
2543 // Walk over the signature of the function
2644 DefKind::AssocFn | DefKind::Fn => {
......@@ -47,24 +65,8 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
4765 | DefKind::Static { .. }
4866 | DefKind::Const { .. }
4967 | 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(),
6870 DefKind::OpaqueTy => {
6971 for (pred, span) in tcx
7072 .explicit_item_bounds(item)
compiler/rustc_type_ir/src/interner.rs+2-3
......@@ -16,7 +16,7 @@ use crate::solve::{
1616 AccessedOpaques, CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect,
1717};
1818use crate::visit::{Flags, TypeVisitable};
19use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph};
19use crate::{self as ty, CanonicalParamEnvCacheEntry, TraitRef, search_graph};
2020
2121#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_interner")]
2222pub trait Interner:
......@@ -398,8 +398,7 @@ pub trait Interner:
398398
399399 fn for_each_relevant_impl<R: VisitorResult>(
400400 self,
401 trait_def_id: Self::TraitId,
402 self_ty: Self::Ty,
401 trait_ref: TraitRef<Self>,
403402 f: impl FnMut(Self::ImplId) -> R,
404403 ) -> R;
405404 fn for_each_blanket_impl<R: VisitorResult>(
library/alloc/src/io/error.rs+3
......@@ -55,6 +55,7 @@ impl Error {
5555 /// originate from the OS itself. It is a shortcut for [`Error::new`][new]
5656 /// with [`ErrorKind::Other`].
5757 ///
58 // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
5859 /// [new]: struct.Error.html#method.new
5960 ///
6061 /// # Examples
......@@ -84,6 +85,7 @@ impl Error {
8485 /// then this function will return [`Some`],
8586 /// otherwise it will return [`None`].
8687 ///
88 // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
8789 /// [new]: struct.Error.html#method.new
8890 /// [other]: struct.Error.html#method.other
8991 ///
......@@ -141,6 +143,7 @@ impl Error {
141143 /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by
142144 /// [`Error::into_inner`][into_inner].
143145 ///
146 // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
144147 /// [into_inner]: struct.Error.html#method.into_inner
145148 ///
146149 /// # Examples
library/core/src/io/cursor.rs+2
......@@ -16,6 +16,7 @@
1616/// code, but use an in-memory buffer in our tests. We can do this with
1717/// `Cursor`:
1818///
19// FIXME(#74481): Hard-links required to link from `core` to `std`
1920/// [bytes]: crate::slice "slice"
2021/// [`File`]: ../../std/fs/struct.File.html
2122/// [`Read`]: ../../std/io/trait.Read.html
......@@ -80,6 +81,7 @@ impl<T> Cursor<T> {
8081 /// is not empty. So writing to cursor starts with overwriting [`Vec`]
8182 /// content, not with appending to it.
8283 ///
84 // FIXME(#74481): Hard-links required to link from `core` to `alloc`
8385 /// [`Vec`]: ../../alloc/vec/struct.Vec.html
8486 ///
8587 /// # Examples
library/core/src/io/error.rs+6
......@@ -45,6 +45,7 @@ use crate::{error, fmt, result};
4545/// will generally use `io::Result` instead of shadowing the [prelude]'s import
4646/// of [`core::result::Result`][`Result`].
4747///
48// FIXME(#74481): Hard-links required to link from `core` to `std`
4849/// [`std::io`]: ../../std/io/index.html
4950/// [`io::Error`]: Error
5051/// [`Result`]: crate::result::Result
......@@ -76,6 +77,7 @@ pub type Result<T> = result::Result<T, Error>;
7677/// `Error` can be created with crafted error messages and a particular value of
7778/// [`ErrorKind`].
7879///
80// FIXME(#74481): Hard-links required to link from `core` to `std`
7981/// [Read]: ../../std/io/trait.Read.html
8082/// [Write]: ../../std/io/trait.Write.html
8183/// [Seek]: ../../std/io/trait.Seek.html
......@@ -171,6 +173,7 @@ pub struct SimpleMessage {
171173/// Contrary to [`Error::new`][new], this macro does not allocate and can be used in
172174/// `const` contexts.
173175///
176// FIXME(#74481): Hard-links required to link from `core` to `alloc` for incoherent method
174177/// [new]: ../../alloc/io/struct.Error.html#method.new
175178///
176179/// # Example
......@@ -286,6 +289,7 @@ impl Error {
286289 /// [`from_raw_os_error`][from_raw_os_error], then this function will return [`Some`], otherwise
287290 /// it will return [`None`].
288291 ///
292 // FIXME(#74481): Hard-links required to link from `core` to `std` for incoherent method
289293 /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error
290294 /// [from_raw_os_error]: ../../std/io/struct.Error.html#method.from_raw_os_error
291295 ///
......@@ -366,6 +370,7 @@ impl Error {
366370 /// If this [`Error`] was constructed via [`new`][new] then this function will
367371 /// return [`Some`], otherwise it will return [`None`].
368372 ///
373 // FIXME(#74481): Hard-links required to link from `core` to `std`
369374 /// [new]: ../../alloc/io/struct.Error.html#method.new
370375 ///
371376 /// # Examples
......@@ -441,6 +446,7 @@ impl Error {
441446 /// it will be a value inferred from the system's error encoding.
442447 /// See [`last_os_error`][last_os_error] for more details.
443448 ///
449 // FIXME(#74481): Hard-links required to link from `core` to `std`
444450 /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error
445451 ///
446452 /// # Examples
src/bootstrap/src/core/build_steps/test.rs+52-23
......@@ -10,6 +10,7 @@ use std::collections::HashSet;
1010use std::env::split_paths;
1111use std::ffi::{OsStr, OsString};
1212use std::path::{Path, PathBuf};
13use std::process::Command;
1314use std::{env, fs, iter};
1415
1516use build_helper::exit;
......@@ -2474,7 +2475,13 @@ Please disable assertions with `rust.debug-assertions = false`.
24742475 "-Lnative={}",
24752476 builder.test_helpers_out(test_compiler.host).display()
24762477 ));
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 }
24782485 }
24792486
24802487 for flag in hostflags {
......@@ -4120,32 +4127,54 @@ impl Step for TestHelpers {
41204127 };
41214128 let dst = builder.test_helpers_out(target);
41224129 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
41274130 let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target);
41284131 t!(fs::create_dir_all(&dst));
4129 let mut cfg = cc::Build::new();
41304132
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;
41374159 }
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 }
41494178 }
41504179}
41514180
src/bootstrap/src/core/config/target_selection.rs+4
......@@ -78,6 +78,10 @@ impl TargetSelection {
7878 self.contains("msvc")
7979 }
8080
81 pub fn is_pauthtest(&self) -> bool {
82 self.contains("pauthtest")
83 }
84
8185 pub fn is_windows(&self) -> bool {
8286 self.contains("windows")
8387 }
src/bootstrap/src/core/sanity.rs+49-1
......@@ -21,7 +21,7 @@ use crate::builder::Kind;
2121use crate::core::build_steps::tool;
2222use crate::core::config::{CompilerBuiltins, Target};
2323use crate::utils::exec::command;
24use crate::{Build, Subcommand};
24use crate::{Build, Subcommand, t};
2525
2626pub struct Finder {
2727 cache: HashMap<OsString, Option<PathBuf>>,
......@@ -38,6 +38,7 @@ pub struct Finder {
3838const STAGE0_MISSING_TARGETS: &[&str] = &[
3939 // just a dummy comment so the list doesn't get onelined
4040 "powerpc64-unknown-linux-gnuelfv2",
41 "aarch64-unknown-linux-pauthtest", // Stage 0 compiler is not guaranteed to see the target yet.
4142];
4243
4344/// Minimum version threshold for libstdc++ required when using prebuilt LLVM
......@@ -412,6 +413,53 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
412413 {
413414 cmd_finder.must_have("wasm-component-ld");
414415 }
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 }
415463 }
416464
417465 if let Some(ref s) = build.config.ccache {
src/doc/rustc/src/SUMMARY.md+1
......@@ -49,6 +49,7 @@
4949 - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
5050 - [aarch64-unknown-linux-gnu](platform-support/aarch64-unknown-linux-gnu.md)
5151 - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md)
52 - [aarch64-unknown-linux-pauthtest](platform-support/aarch64-unknown-linux-pauthtest.md)
5253 - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md)
5354 - [aarch64v8r-unknown-none*](platform-support/aarch64v8r-unknown-none.md)
5455 - [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
271271[`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit
272272[`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos
273273`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
274275[`aarch64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | ARM64 Managarm
275276[`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD
276277[`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
5This target enables Pointer Authentication Code (PAC) support in Rust on AArch64
6ELF-based Linux systems. It uses the `aarch64-unknown-linux-pauthtest` LLVM
7target and a pointer-authentication-enabled sysroot with a custom musl as a
8reference libc implementation. Dynamic linking is required, with a dynamic
9linker acting as the ELF interpreter that can resolve pauth relocations and
10enforce pointer authentication constraints.
11
12Supported 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
27A tracking issue for adding support for the AArch64 pointer authentication ABI
28in Rust can be found at
29[#148640](https://github.com/rust-lang/rust/issues/148640).
30
31Existing compiler support, such as enabling branch authentication instructions
32(i.e.: `-Z branch-protection`) provide limited functionality, mainly signing
33return addresses (`pac-ret`). The new target goes further by enabling ABI-level
34pointer authentication support.
35
36This target does not define a new ABI; it builds on the existing C/C++ language
37ABI with pointer authentication support added. However, different authentication
38features, encoded in the signing schema, are not ABI-compatible with one
39another.
40
41Useful 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
55This target supports cross-compilation from any Linux host, but execution
56requires AArch64 with pointer authentication support (ARMv8.3-A or higher).
57
58## Standard library support
59
60Full std support is available: `core`, `alloc`, and `std` all build
61successfully. All library tests (`core`, `alloc`, `std`) pass for this target as
62well.
63
64## Building the toolchain
65
66Building this target requires a pointer-authentication-enabled sysroot based on
67a custom musl toolchain. The sysroot must be available on the system before
68compilation. To build it, follow the instructions in the [build scripts
69repo](https://github.com/access-softek/pauth-toolchain-build-scripts).
70
71The target uses Clang, please make sure it is `v22.1.0` or higher. When using a
72system-provided Clang, a compiler wrapper is required to supply the necessary
73flags. Please consult the listing:
74
75```sh
76#!/usr/bin/env sh
77
78clang \
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
91Bootstrap validates the name of the configured C compiler, so when using a
92wrapper 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
98To 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
104When using the AccessSoftek scripts to build the sysroot, the result includes a
105Clang-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
110Introduction of `aarch64-unknown-linux-pauthtest` target needs to be propagated
111to various crates/repos, so that they can correctly recognise and handle it.
112Specifically:
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
117The 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
121details:
122
123<details>
124
125```diff
126diff --git a/library/Cargo.toml b/library/Cargo.toml
127index 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' }
135diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
136index 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
150In 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
154has not yet been committed there, which means an in-tree patch is currently
155required. The patch:
156
157<details>
158
159```diff
160diff --git a/src/backtrace/libunwind.rs b/src/backtrace/libunwind.rs
161index 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
191The target can be built by enabling it for a `rustc` build.
192
193```toml
194[build]
195target = ["aarch64-unknown-linux-pauthtest"]
196```
197
198Specify the binaries used by the target.
199
200```toml
201[target.aarch64-unknown-linux-pauthtest]
202cc = "<path_to>/aarch64-unknown-linux-pauthtest-clang"
203ar = "<path_to>/llvm-ar"
204ranlib = "<path_to>/llvm-ranlib"
205linker = "<path_to>/aarch64-unknown-linux-pauthtest-clang"
206```
207
208Note that `cc` and `linker` must refer to the same binary (either Clang itself
209or its wrapper). The bootstrap process will fail if they differ. On non-AArch64
210systems, ensure that QEMU is installed and that `binfmt_misc` is correctly
211configured so that foreign architecture binaries can be executed transparently.
212
213## Building Rust programs
214
215Rust does not currently ship precompiled artifacts for this target. Programs
216must be built using a locally compiled Rust toolchain, with
217`aarch64-unknown-linux-pauthtest` target enabled.
218
219For a comprehensive example of how to interact between C and Rust programs
220within the testing framework please consult
221`<rust_root>/tests/run-make/pauth-quicksort-c-driver/rmake.rs`, the test builds
222a C executable linked against Rust library.
223`<rust_root>/tests/run-make/pauth-quicksort-rust-driver/rmake.rs` shows how to
224link a Rust program against a library compiled from a C source file.
225
226### Minimal standalone Rust and C interoperability example
227
228A 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
236rust_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]
250name = "rust_c_indirect"
251edition = "2024"
252build = "build.rs"
253```
254
255* `build.rs`
256
257```rust, ignore (platform-specific)
258use std::env;
259use std::path::Path;
260use std::process::Command;
261
262fn 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)
290use std::ptr;
291use std::os::raw::c_int;
292
293unsafe extern "C" {
294 fn add(a: c_int, b: c_int) -> c_int;
295}
296
297static OP: unsafe extern "C" fn(c_int, c_int) -> c_int = add;
298
299fn 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
313int 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
321Please 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
325To 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`.
328Relevant 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
337Which 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
343Note, when building crates it is necessary to explicitly point Cargo to the
344linker it has to use. This can be achieved by using a `config.toml` file (either
345local 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]
351linker = "<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
356Without it Cargo falls back to the system C toolchain (cc) and the compilation
357fails.
358
359## Cross-compilation toolchains and C code
360
361This target supports interoperability with C code. A
362pointer-authentication-enabled sysroot, built as described in the toolchain
363build section of this document, is required. C code must be compiled with a
364compiler configuration that supports pointer authentication. Mixed Rust/C
365programs are supported and tested (e.g. quicksort examples). Pointer
366authentication semantics must be consistent across Rust and C components. Only
367dynamic linking is supported.
368
369The target can be cross-compiled from any Linux-based host, but execution
370requires an AArch64 system that implements Pointer Authentication (PAC). In
371practice, this means a CPU conforming to at least the Armv8.3-A architecture,
372where 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)
374extension is defined.
375
376Cross-compilation has been successfully performed on both
377`aarch64-unknown-linux-gnu` and `x86_64-unknown-linux-gnu` hosts.
378
379## Testing
380
381This target can be tested as normal with `x.py`.
382The 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
398All 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
402Command to run all passing tests (with tests added by this target explicitly
403named for convenience):
404
405```sh
406x.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
423Operand bundles should only be attached to indirect function calls. However,
424function pointer signing is currently performed in `get_fn_addr`, which causes
425the logic to be applied too broadly, including to function values (not just
426pointers). As a result, direct calls using signed function values must also
427receive operand bundles. Once this is resolved, we should analyze each call and
428skip direct calls.
429For more information please see the discussion in the [rust-lang issue
430tracker](https://github.com/rust-lang/rust/issues/152532).
431
432The current version only supports C interoperability with pointer authentication
433features explicitly mentioned at the beginning of this document. Further work is
434needed to support configurable signing schemas (i.e. selection of signing keys,
435discriminators, address diversity, and features opt-in/opt-out) as defined by
436the LLVM pointer authentication model.
437
438C++ interoperability is not currently supported. Features such as signing C++
439member function pointers, virtual function pointers, and virtual table pointers
440are 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
3This 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
5The recursion limit affects (among other things):
6
7- macro expansion
8- the trait solver
9- const evaluation
10- query depth
11
12This 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
3This 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
5The recursion limit affects (among other things):
6
7- macro expansion
8- the trait solver
9- const evaluation
10- query depth
11
12This 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 {
270270 }
271271}
272272
273impl 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
273285impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> {
274286 fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
275287 use clean::GenericArgs::*;
......@@ -353,18 +365,23 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum
353365 EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)),
354366 VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)),
355367 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))
357369 }
358370 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))
360372 }
361373 TraitItem(t) => ItemEnum::Trait(t.into_json(renderer)),
362374 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 )),
366383 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))
368385 }
369386 ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
370387 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
385402 })
386403 }
387404 // 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 },
391410 // FIXME(generic_const_items): Add support for generic associated consts.
392 ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst {
411 ProvidedAssocConstItem(ci) => ItemEnum::AssocConst {
393412 type_: ci.type_.into_json(renderer),
394413 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,
395424 },
396425 RequiredAssocTypeItem(g, b) => ItemEnum::AssocType {
397426 generics: g.into_json(renderer),
398427 bounds: b.into_json(renderer),
399428 type_: None,
429 default_unstable: None,
400430 },
401431 AssocTypeItem(t, b) => ItemEnum::AssocType {
402432 generics: t.generics.into_json(renderer),
403433 bounds: b.into_json(renderer),
404434 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)),
405440 },
406441 // `convert_item` early returns `None` for stripped items, keywords, attributes and
407442 // "special" macro rules.
......@@ -815,6 +850,7 @@ impl FromClean<clean::Impl> for Impl {
815850pub(crate) fn from_clean_function(
816851 clean::Function { decl, generics }: &clean::Function,
817852 has_body: bool,
853 default_unstable: Option<Box<ProvidedDefaultUnstable>>,
818854 header: rustc_hir::FnHeader,
819855 renderer: &JsonRenderer<'_>,
820856) -> Function {
......@@ -823,6 +859,7 @@ pub(crate) fn from_clean_function(
823859 generics: generics.into_json(renderer),
824860 header: header.into_json(renderer),
825861 has_body,
862 default_unstable,
826863 }
827864}
828865
......@@ -972,6 +1009,17 @@ impl FromClean<ItemType> for ItemKind {
9721009 }
9731010}
9741011
1012fn 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
9751023fn const_stability_for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::ConstStability> {
9761024 if !tcx.is_conditionally_const(def_id) {
9771025 // 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<'_>)
10401088 AK::Deprecated { .. } => return Vec::new(), // Handled separately into Item::deprecation.
10411089 AK::Stability { .. } => return Vec::new(), // Handled separately into Item::stability
10421090 AK::RustcConstStability { .. } => return Vec::new(), // Handled separately into Item::const_stability.
1091 AK::RustcBodyStability { .. } => return Vec::new(), // Handled separately by `default_unstable`.
10431092
10441093 AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"),
10451094
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
114114// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
115115// are deliberately not in a doc comment, because they need not be in public docs.)
116116//
117// Latest feature: Add `Item::const_stability`.
118pub const FORMAT_VERSION: u32 = 59;
117// Latest feature: Add default-body stability metadata.
118pub const FORMAT_VERSION: u32 = 60;
119119
120120/// The root of the emitted JSON blob.
121121///
......@@ -288,6 +288,9 @@ pub struct Item {
288288 /// - `#[stable]` and `#[unstable]` attributes: see the [`Self::stability`] field instead.
289289 /// - `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes:
290290 /// 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`].
291294 ///
292295 /// Attributes appear in pretty-printed Rust form, regardless of their formatting
293296 /// in the original source code. For example:
......@@ -367,6 +370,19 @@ pub enum StabilityLevel {
367370 Unstable,
368371}
369372
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)))]
381pub struct ProvidedDefaultUnstable {
382 /// The feature that must be enabled to use the provided default.
383 pub feature: String,
384}
385
370386#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
371387#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
372388#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))]
......@@ -379,6 +395,9 @@ pub enum StabilityLevel {
379395/// - `#[stable]` and `#[unstable]`. These are in [`Item::stability`] instead.
380396/// - `#[rustc_const_stable]` and `#[rustc_const_unstable]`. These are in
381397/// [`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`].
382401pub enum Attribute {
383402 /// `#[non_exhaustive]`
384403 NonExhaustive,
......@@ -875,6 +894,11 @@ pub enum ItemEnum {
875894 /// // ^^^^^^^^^^
876895 /// ```
877896 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>>,
878902 },
879903 /// An associated type of a trait or a type.
880904 AssocType {
......@@ -899,6 +923,11 @@ pub enum ItemEnum {
899923 /// ```
900924 #[serde(rename = "type")]
901925 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>>,
902931 },
903932}
904933
......@@ -1188,6 +1217,12 @@ pub struct Function {
11881217 pub header: FunctionHeader,
11891218 /// Whether the function has a body, i.e. an implementation.
11901219 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>>,
11911226}
11921227
11931228/// 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] = &[
106106 "ignore-nvptx64-nvidia-cuda",
107107 "ignore-openbsd",
108108 "ignore-parallel-frontend",
109 "ignore-pauthtest",
109110 "ignore-powerpc",
110111 "ignore-powerpc64",
111112 "ignore-remote",
......@@ -247,6 +248,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
247248 "only-musl",
248249 "only-nightly",
249250 "only-nvptx64",
251 "only-pauthtest",
250252 "only-powerpc",
251253 "only-riscv32",
252254 "only-riscv64",
src/tools/jsondoclint/src/validator.rs+39-4
......@@ -97,7 +97,7 @@ impl<'a> Validator<'a> {
9797 ItemEnum::StructField(x) => self.check_struct_field(x),
9898 ItemEnum::Enum(x) => self.check_enum(x),
9999 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),
101101 ItemEnum::Trait(x) => self.check_trait(x, id),
102102 ItemEnum::TraitAlias(x) => self.check_trait_alias(x),
103103 ItemEnum::Impl(x) => self.check_impl(x, id),
......@@ -114,12 +114,35 @@ impl<'a> Validator<'a> {
114114 ItemEnum::Module(x) => self.check_module(x, id),
115115 // FIXME: Why don't these have their own structs?
116116 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 } => {
119133 self.check_generics(generics);
120134 bounds.iter().for_each(|b| self.check_generic_bound(b));
121135 if let Some(ty) = type_ {
122136 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 );
123146 }
124147 }
125148 }
......@@ -194,9 +217,21 @@ impl<'a> Validator<'a> {
194217 }
195218 }
196219
197 fn check_function(&mut self, x: &'a Function) {
220 fn check_function(&mut self, x: &'a Function, id: &Id) {
198221 self.check_generics(&x.generics);
199222 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 }
200235 }
201236
202237 fn check_trait(&mut self, x: &'a Trait, id: &Id) {
src/tools/jsondoclint/src/validator/tests.rs+153-1
......@@ -1,5 +1,7 @@
11use rustc_hash::FxHashMap;
2use rustdoc_json_types::{Abi, FORMAT_VERSION, FunctionHeader, Item, ItemKind, Visibility};
2use rustdoc_json_types::{
3 Abi, FORMAT_VERSION, FunctionHeader, Item, ItemKind, ProvidedDefaultUnstable, Visibility,
4};
35
46use super::*;
57use crate::json_find::SelectorPart;
......@@ -221,6 +223,7 @@ fn errors_on_missing_path() {
221223 abi: Abi::Rust,
222224 },
223225 has_body: true,
226 default_unstable: None,
224227 }),
225228 },
226229 ),
......@@ -246,6 +249,155 @@ fn errors_on_missing_path() {
246249 );
247250}
248251
252fn 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]
331fn 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]
359fn 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]
380fn 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
249401#[test]
250402#[should_panic = "LOCAL_CRATE_ID is wrong"]
251403fn checks_local_crate_id_is_correct() {
src/tools/run-make-support/Cargo.toml+1-1
......@@ -13,7 +13,7 @@ edition = "2024"
1313bstr = "1.12"
1414gimli = "0.32"
1515libc = "0.2"
16object = "0.37"
16object = { version = "0.37", features = ["wasm"] }
1717regex = "1.11"
1818serde_json = "1.0"
1919similar = "2.7"
tests/assembly-llvm/asm/aarch64-outline-atomics.rs+3
......@@ -2,6 +2,9 @@
22//@ compile-flags: -Copt-level=3
33//@ only-aarch64
44//@ 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
58
69#![crate_type = "rlib"]
710
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
13extern crate minicore;
14
15#[no_mangle]
16#[inline(never)]
17pub extern "C" fn c_func(a: i32) -> i32 {
18 a
19}
20
21#[no_mangle]
22#[inline(never)]
23fn call_through(f: extern "C" fn(i32) -> i32, x: i32) -> i32 {
24 f(x)
25}
26
27#[no_mangle]
28#[inline(never)]
29pub 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 @@
5555//@ revisions: aarch64_unknown_linux_ohos
5656//@ [aarch64_unknown_linux_ohos] compile-flags: --target aarch64-unknown-linux-ohos
5757//@ [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
5861//@ revisions: aarch64_unknown_managarm_mlibc
5962//@ [aarch64_unknown_managarm_mlibc] compile-flags: --target aarch64-unknown-managarm-mlibc
6063//@ [aarch64_unknown_managarm_mlibc] needs-llvm-components: aarch64
tests/auxiliary/minicore.rs+23
......@@ -8,7 +8,10 @@
88//! items. For identical error output, any `diagnostic` attributes (e.g. `on_unimplemented`)
99//! should also be replicated here.
1010//! - 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).
1113//!
14
1215//! # References
1316//!
1417//! This is partially adapted from `rustc_codegen_cranelift`:
......@@ -299,6 +302,16 @@ impl_marker_trait!(
299302impl Sync for () {}
300303
301304impl<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.
310impl<R> Sync for fn() -> R {}
311impl<R> Sync for extern "C" fn() -> R {}
312impl<R> Sync for unsafe extern "C" fn() -> R {}
313impl<A, R> Sync for extern "C" fn(A) -> R {}
314impl<A, R> Sync for unsafe extern "C" fn(A) -> R {}
302315
303316#[lang = "drop_glue"]
304317fn drop_glue<T>(_: &mut T) {}
......@@ -367,6 +380,16 @@ pub mod ptr {
367380 }
368381}
369382
383pub 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
370393#[lang = "c_void"]
371394#[repr(u8)]
372395pub enum c_void {
tests/codegen-llvm/box-uninit-bytes.rs+1-1
......@@ -43,4 +43,4 @@ pub fn box_lotsa_padding() -> Box<LotsaPadding> {
4343// from the CHECK-NOT above, and also verify the attributes got set reasonably.
4444// 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]+]]
4545
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 @@
11//@ needs-unwind
22//@ 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
37
48#![crate_type = "lib"]
59#![feature(c_variadic)]
tests/codegen-llvm/inline-always-works-always.rs+2
......@@ -2,6 +2,8 @@
22//@[NO-OPT] compile-flags: -Copt-level=0
33//@[SIZE-OPT] compile-flags: -Copt-level=s
44//@[SPEED-OPT] compile-flags: -Copt-level=3
5// Pointer authenticated calls are not guaranteed to be inlined.
6//@ ignore-pauthtest
57
68#![crate_type = "rlib"]
79
tests/codegen-llvm/issues/issue-73258.rs+5-3
......@@ -3,6 +3,8 @@
33#![crate_type = "lib"]
44
55// 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.
68
79#[derive(Clone, Copy)]
810#[repr(u8)]
......@@ -17,7 +19,7 @@ pub enum Foo {
1719#[no_mangle]
1820pub unsafe fn issue_73258(ptr: *const Foo) -> Foo {
1921 // CHECK-NOT: icmp
20 // CHECK-NOT: call
22 // CHECK-NOT: call{{.*}}(
2123 // CHECK-NOT: br {{.*}}
2224 // CHECK-NOT: select
2325
......@@ -25,14 +27,14 @@ pub unsafe fn issue_73258(ptr: *const Foo) -> Foo {
2527 // CHECK-SAME: !range !
2628
2729 // CHECK-NOT: icmp
28 // CHECK-NOT: call
30 // CHECK-NOT: call{{.*}}(
2931 // CHECK-NOT: br {{.*}}
3032 // CHECK-NOT: select
3133
3234 // CHECK: ret i8 %[[R]]
3335
3436 // CHECK-NOT: icmp
35 // CHECK-NOT: call
37 // CHECK-NOT: call{{.*}}(
3638 // CHECK-NOT: br {{.*}}
3739 // CHECK-NOT: select
3840 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
9use 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"
25fn 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
18extern crate minicore;
19use minicore::hint::black_box;
20use minicore::*;
21
22extern "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
34type CFnPtr = unsafe extern "C" fn(i32, i32) -> i32;
35
36// CHECK-LABE: test_indirect_call
37#[inline(never)]
38fn 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)]
77fn 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
92pub 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
25extern crate minicore;
26
27type 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]
34pub 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)]
43pub 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
49extern "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
21extern crate minicore;
22use 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
31extern "C" {
32 #[link_name = "extern_weak_fn"]
33 #[linkage = "extern_weak"]
34 fn extern_weak_fn() -> i64;
35}
36
37#[used]
38static 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
18extern crate minicore;
19use 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"]
25static 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"]
31static GLOBAL_FINI: extern "C" fn(i32) = fini_fn;
32
33extern "C" fn init_fn() {}
34extern "C" fn fini_fn(_: i32) {}
tests/run-make/c-link-to-rust-va-list-fn/rmake.rs+2
......@@ -6,6 +6,8 @@
66//@ needs-target-std
77//@ ignore-android: FIXME(#142855)
88//@ 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).
911
1012use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name};
1113
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
6void quickSort(void *Base, size_t N, size_t Size,
7 int (*Cmp)(const void *, const void *));
8
9#ifdef __cplusplus
10}
11#endif
12
13int 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
25int 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 @@
1use std::mem::size_of;
2use std::os::raw::{c_int, c_void};
3use std::ptr;
4
5unsafe fn swap_i32(lhs: *mut i32, rhs: *mut i32) {
6 ptr::swap(lhs, rhs);
7}
8
9unsafe 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
37unsafe 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]
51pub 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
9use run_make_support::{cc, env_var, rfs, run, run_fail, rustc};
10
11fn 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 @@
1use std::os::raw::{c_int, c_void};
2
3#[link(name = "quicksort")]
4extern "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
13extern "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
28fn 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
5void 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
12int 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
35void 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
44void 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
9use run_make_support::{cc, env_var, rfs, run, run_fail, rustc};
10
11fn 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 @@
1int 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")]
2extern "C" {
3 fn helper_function() -> i32;
4}
5
6fn 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 @@
1extern "C" {
2 fn helper_function() -> i32;
3}
4
5fn 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
8use run_make_support::{cc, env_var, regex, run, rustc};
9
10fn 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() {
2727 // so only exercise the success path when the target can run on the host.
2828 if target().contains("wasm")
2929 || target().contains("sgx")
30 || target().contains("pauthtest")
3031 || std::env::var_os("REMOTE_TEST_CLIENT").is_some()
3132 {
3233 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
11use run_make_support::object::read::Object;
12use run_make_support::object::read::archive::ArchiveFile;
13use run_make_support::object::{self, Architecture};
14use run_make_support::{has_extension, has_prefix, rfs, rustc, shallow_find_files};
15
16fn 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")]
4pub 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")]
54pub 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")]
58impl 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`
129129LL | target_abi = "_UNEXPECTED_VALUE",
130130 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
131131 |
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`
133133 = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
134134
135135warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
tests/ui/codegen/huge-stacks.rs+2-1
......@@ -5,6 +5,7 @@
55//@ min-llvm-version: 22
66
77// 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
89
910fn func() {
1011 const CAP: usize = std::u32::MAX as usize;
......@@ -17,7 +18,7 @@ fn main() {
1718 std::thread::Builder::new()
1819 .stack_size(5 * 1024 * 1024 * 1024)
1920 .spawn(func)
20 .unwrap()
21 .expect("huge-stacks.rs requires 5GB RAM to run")
2122 .join()
2223 .unwrap();
2324}
tests/ui/const-generics/mgca/double-inline-const.rs created+11
......@@ -0,0 +1,11 @@
1#![feature(min_generic_const_args)]
2
3struct S<const N: usize>;
4
5impl<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
11fn main() {}
tests/ui/const-generics/mgca/double-inline-const.stderr created+15
......@@ -0,0 +1,15 @@
1error: generic `Self` types are currently not permitted in anonymous constants
2 --> $DIR/double-inline-const.rs:7:35
3 |
4LL | fn foo(_: S<{ const { const { Self::Q } } }>) {}
5 | ^^^^
6 |
7note: not a concrete type
8 --> $DIR/double-inline-const.rs:5:22
9 |
10LL | 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
14error: aborting due to 1 previous error
15
tests/ui/process/nofile-limit.rs+3
......@@ -8,6 +8,9 @@
88//@ no-prefer-dynamic
99//@ compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static
1010//@ 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
1114
1215#![feature(exit_status_error)]
1316#![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 @@
1error: pointer authentication requires dynamic linking. Statically linked libc is incompatible, disable it using `-C target-feature=-crt-static`
2
3error: 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
4fn 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 @@
1error[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 |
4LL | 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
9help: function arguments must have a statically known size, borrowed types always have a known size
10 |
11LL | let f = |f: &dyn Fn()| f;
12 | +
13
14error[E0746]: return type cannot be a trait object without pointer indirection
15 --> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:27
16 |
17LL | let f = |f: dyn Fn()| f;
18 | ^ doesn't have a size known at compile-time
19
20error[E0057]: this function takes 1 argument but 0 arguments were supplied
21 --> $DIR/deferred-closure-call-recovery-issue-157951.rs:8:5
22 |
23LL | f();
24 | ^-- argument #1 of type `(dyn Fn() + 'static)` is missing
25 |
26note: closure defined here
27 --> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:13
28 |
29LL | let f = |f: dyn Fn()| f;
30 | ^^^^^^^^^^^^^
31help: provide the argument
32 |
33LL | f(/* (dyn Fn() + 'static) */);
34 | ++++++++++++++++++++++++++
35
36error: aborting due to 3 previous errors
37
38Some errors have detailed explanations: E0057, E0277, E0746.
39For more information about an error, try `rustc --explain E0057`.