From 70ac00e3b6cc7a23db549642b23f3c5b811e6a02 Mon Sep 17 00:00:00 2001 From: Ramon de C Valle Date: Wed, 25 Oct 2023 12:46:20 -0700 Subject: [PATCH] CFI: Fix fn items, closures, and Fn trait objects Fix casting between function items, closures, and Fn trait objects by transforming function items, closures, and Fn trait objects into function pointers for encoding. --- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 10 + compiler/rustc_symbol_mangling/src/lib.rs | 1 + .../src/typeid/typeid_itanium_cxx_abi.rs | 419 +++++++++++++++--- ...pe-metadata-id-itanium-cxx-abi-closures.rs | 55 +++ ...tanium-cxx-abi-closure-decl-def-vs-call.rs | 17 + ...anium-cxx-abi-fn-trait-decl-def-vs-call.rs | 17 + ...adata-id-itanium-cxx-abi-function-types.rs | 38 +- ...-type-metadata-id-itanium-cxx-abi-paths.rs | 12 +- ...metadata-id-itanium-cxx-abi-trait-types.rs | 13 +- tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs | 14 +- .../ui/sanitizer/cfi-closure-fn-trait-cast.rs | 13 + .../sanitizer/cfi-dynamic-fn-subtrait-call.rs | 18 + 13 files changed, 525 insertions(+), 104 deletions(-) create mode 100644 tests/codegen/sanitizer/cfi/cfi-emit-type-metadata-id-itanium-cxx-abi-closures.rs create mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-closure-decl-def-vs-call.rs create mode 100644 tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-fn-trait-decl-def-vs-call.rs create mode 100644 tests/ui/sanitizer/cfi-closure-fn-trait-cast.rs create mode 100644 tests/ui/sanitizer/cfi-dynamic-fn-subtrait-call.rs diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3393f44484388..258c533018076 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1841,7 +1841,7 @@ impl<'tcx> TyCtxt<'tcx> { /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used /// to identify which traits may define a given associated type to help avoid cycle errors. /// Returns a `DefId` iterator. - fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator + 'tcx { + pub fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator + 'tcx { let mut set = FxHashSet::default(); let mut stack = vec![trait_def_id]; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c85ee140fa4ec..f5e048027cb0f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1836,6 +1836,11 @@ impl<'tcx> Ty<'tcx> { self.0.0.flags } + #[inline] + pub fn is_tuple(self) -> bool { + matches!(self.kind(), Tuple(..)) + } + #[inline] pub fn is_unit(self) -> bool { match self.kind() { @@ -2208,6 +2213,11 @@ impl<'tcx> Ty<'tcx> { matches!(self.kind(), FnDef(..) | FnPtr(_)) } + #[inline] + pub fn is_fn_def(self) -> bool { + matches!(self.kind(), FnDef(..)) + } + #[inline] pub fn is_fn_ptr(self) -> bool { matches!(self.kind(), FnPtr(_)) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 0588af9bda72a..866738d48ee0e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -92,6 +92,7 @@ #![feature(rustdoc_internals)] #![feature(let_chains)] #![allow(internal_features)] +#![feature(iter_order_by)] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 3101015281b82..a6d5dee5e4278 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -642,19 +642,8 @@ fn encode_ty<'tcx>( // Function types ty::FnDef(def_id, args) - | ty::Closure(def_id, args) + | ty::Coroutine(def_id, args, ..) | ty::CoroutineClosure(def_id, args) => { - // u[IE], where is , - // as vendor extended type. - let mut s = String::new(); - let name = encode_ty_name(tcx, *def_id); - let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, args, dict, options)); - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - typeid.push_str(&s); - } - - ty::Coroutine(def_id, args, ..) => { // u[IE], where is , // as vendor extended type. let mut s = String::new(); @@ -735,6 +724,7 @@ fn encode_ty<'tcx>( ty::Alias(..) | ty::Bound(..) | ty::Error(..) + | ty::Closure(..) | ty::CoroutineWitness(..) | ty::Infer(..) | ty::Placeholder(..) => { @@ -745,23 +735,235 @@ fn encode_ty<'tcx>( typeid } -/// Transforms predicates for being encoded and used in the substitution dictionary. -fn transform_predicates<'tcx>( +/// Returns the list of arguments if principal is an Fn trait or Fn subtrait. +#[inline] +fn fn_trait_args<'tcx>( tcx: TyCtxt<'tcx>, predicates: &List>, -) -> &'tcx List> { - tcx.mk_poly_existential_predicates_from_iter(predicates.iter().filter_map(|predicate| { - match predicate.skip_binder() { - ty::ExistentialPredicate::Trait(trait_ref) => { +) -> Option<&'tcx List>> { + if is_fn_trait(tcx, predicates) || is_fn_subtrait(tcx, predicates) { + if let Some(args) = principal_args(predicates) + && !args.is_empty() + && args[0].expect_ty().is_tuple() + { + return Some(args[0].expect_ty().tuple_fields()); + } + if is_fn_subtrait(tcx, predicates) { + return Some(List::empty()); + } else { + bug!("fn_trait_args: unexpected non-tuple arg `{:?}`", principal_args(predicates)); + } + } else { + None + } +} + +/// Returns the output if principal is an Fn trait or Fn subtrait. +#[inline] +fn fn_trait_output<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List>, +) -> Option> { + if is_fn_trait(tcx, predicates) || is_fn_subtrait(tcx, predicates) { + if let Some(projection) = predicates.projection_bounds().next() + && let Some(ty) = projection.skip_binder().term.ty() + { + return Some(ty); + } + if is_fn_subtrait(tcx, predicates) { + return Some(Ty::new_unit(tcx)); + } else { + bug!( + "fn_trait_output: unexpected non-term projection `{:?}`", + predicates.projection_bounds().next() + ); + } + } else { + None + } +} + +/// Returns the signature if principal is an Fn trait or Fn subtrait. +#[inline] +fn fn_trait_sig<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List>, +) -> Option> { + if is_fn_trait(tcx, predicates) || is_fn_subtrait(tcx, predicates) { + Some(tcx.mk_fn_sig( + fn_trait_args(tcx, predicates).unwrap(), + fn_trait_output(tcx, predicates).unwrap(), + false, + hir::Unsafety::Normal, + Abi::Rust, + )) + } else { + None + } +} + +/// Returns true if the trait object is an Fn subtrait object. +#[inline] +fn is_dynamic_fn_subtrait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Dynamic(predicates, ..) => is_fn_subtrait(tcx, predicates), + _ => false, + } +} + +/// Returns true if the trait object is an Fn trait object. +#[inline] +fn is_dynamic_fn_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Dynamic(predicates, ..) => is_fn_trait(tcx, predicates), + _ => false, + } +} + +/// Returns true if principal is an Fn subtrait. +#[inline] +fn is_fn_subtrait<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List>, +) -> bool { + if let Some(principal) = predicates.principal() { + for def_id in tcx.super_traits_of(principal.skip_binder().def_id) { + if tcx.is_fn_trait(def_id) { + return true; + } + } + } + false +} + +/// Returns true if principal is an Fn trait. +#[inline] +fn is_fn_trait<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List>, +) -> bool { + if let Some(principal) = predicates.principal() + && tcx.is_fn_trait(principal.skip_binder().def_id) + { + true + } else { + false + } +} + +/// Returns the principal list of arguments. +#[inline] +fn principal_args<'tcx>( + predicates: &List>, +) -> Option<&'tcx List>> { + predicates.principal().map(|trait_ref| trait_ref.skip_binder().args) +} + +/// Transforms a closure FnAbi for being encoded and used in the substitution dictionary. +fn transform_closure_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _options: EncodeTyOptions, +) -> FnAbi<'tcx, Ty<'tcx>> { + if !fn_abi.args.is_empty() + && let ty::Closure(_, args) = fn_abi.args[0].layout.ty.kind() + { + let fn_sig = tcx.signature_unclosure(args.as_closure().sig(), hir::Unsafety::Normal); + return tcx + .fn_abi_of_fn_ptr(ty::ParamEnv::empty().and((fn_sig, List::empty()))) + .unwrap_or_else(|fn_abi_error| { + bug!("transform_fnabi: couldn't get fn_abi of fn_sig {:?}", fn_abi_error) + }) + .clone(); + } else if !fn_abi.args.is_empty() { + match fn_abi.args[0].layout.ty.kind() { + ty::RawPtr(ty, ..) | ty::Ref(_, ty, _) => { + if let ty::Closure(_, args) = ty.kind() { + let fn_sig = + tcx.signature_unclosure(args.as_closure().sig(), hir::Unsafety::Normal); + return tcx + .fn_abi_of_fn_ptr(ty::ParamEnv::empty().and((fn_sig, List::empty()))) + .unwrap_or_else(|fn_abi_error| { + bug!( + "transform_fnabi: couldn't get fn_abi of fn_sig {:?}", + fn_abi_error + ) + }) + .clone(); + } + } + _ => {} + } + } + + return fn_abi.clone(); +} + +/// Transforms a Fn trait FnAbi for being encoded and used in the substitution dictionary. +fn transform_fn_trait_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _options: EncodeTyOptions, +) -> FnAbi<'tcx, Ty<'tcx>> { + if !fn_abi.args.is_empty() { + let fn_sig = ty::Binder::bind_with_vars( + tcx.mk_fn_sig( + fn_abi.args[1..].iter().map(|arg| arg.layout.ty), + fn_abi.ret.layout.ty, + false, + hir::Unsafety::Normal, + Abi::Rust, + ), + List::empty(), + ); + return tcx + .fn_abi_of_fn_ptr(ty::ParamEnv::empty().and((fn_sig, List::empty()))) + .unwrap_or_else(|fn_abi_error| { + bug!("transform_fnabi: couldn't get fn_abi of fn_sig {:?}", fn_abi_error) + }) + .clone(); + } + return fn_abi.clone(); +} + +/// Transforms a predicate for being encoded and used in the substitution dictionary. +fn transform_predicate<'tcx>( + tcx: TyCtxt<'tcx>, + predicate: ty::PolyExistentialPredicate<'tcx>, + _options: EncodeTyOptions, +) -> Option> { + match predicate.as_ref().skip_binder() { + ty::ExistentialPredicate::Trait(trait_ref) => { + if tcx.is_fn_trait(trait_ref.def_id) { + // Fn trait objects are transformed into function pointers in transform_ty + bug!("transform_predicate: unexpected Fn trait `{}`", trait_ref) + } else { + // Transform non Fn trait objects into their identities let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id); Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), ))) } - ty::ExistentialPredicate::Projection(..) => None, - ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), } - })) + ty::ExistentialPredicate::Projection(..) => None, + ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), + } +} + +/// Transforms predicates for being encoded and used in the substitution dictionary. +fn transform_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List>, + options: EncodeTyOptions, +) -> &'tcx List> { + let mut predicates: Vec> = predicates + .iter() + .filter_map(|predicate| transform_predicate(tcx, predicate, options)) + .collect(); + + // Enforce predicates ordering when encoding + predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); + tcx.mk_poly_existential_predicates(&predicates) } /// Transforms args for being encoded and used in the substitution dictionary. @@ -779,10 +981,20 @@ fn transform_args<'tcx>( tcx.mk_args_from_iter(args) } -// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all -// c_void types into unit types unconditionally, generalizes pointers if -// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if -// TransformTyOptions::NORMALIZE_INTEGERS option is set. +/// Transforms a ty:Ty for being encoded and used in the substitution dictionary. +/// +/// * Transforms all c_void types into unit types. +/// * Generalizes pointers if TransformTyOptions::GENERALIZE_POINTERS option is set. +/// * Normalizes integers if TransformTyOptions::NORMALIZE_INTEGERS option is set. +/// * Generalizes any repr(transparent) user-defined type that is either a pointer or reference, and +/// either references itself or any other type that contains or references itself, to avoid a +/// reference cycle. +/// * Transforms repr(transparent) types without non-ZST field into (). +/// * Transforms function items into function pointers. +/// * Transforms closures into function pointers. +/// * Transforms async closures into function pointers. +/// * Transforms Fn trait objects into function pointers. +/// fn transform_ty<'tcx>( tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>, @@ -790,7 +1002,14 @@ fn transform_ty<'tcx>( options: TransformTyOptions, ) -> Ty<'tcx> { match ty.kind() { - ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {} + ty::Coroutine(..) + | ty::CoroutineClosure(..) + | ty::Float(..) + | ty::FnDef(..) + | ty::Str + | ty::Never + | ty::Foreign(..) + | ty::Param(..) => {} ty::Bool => { if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { @@ -914,38 +1133,43 @@ fn transform_ty<'tcx>( } } - ty::FnDef(def_id, args) => { - ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options)); - } - - ty::Closure(def_id, args) => { - ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options)); - } - - ty::CoroutineClosure(def_id, args) => { - ty = Ty::new_coroutine_closure( - tcx, - *def_id, - transform_args(tcx, args, parents, options), - ); - } - - ty::Coroutine(def_id, args) => { - ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options)); + ty::Closure(_, args) => { + // Transform closures into function pointers + let fn_sig = tcx.signature_unclosure(args.as_closure().sig(), hir::Unsafety::Normal); + let fn_ptr = Ty::new_fn_ptr(tcx, fn_sig); + // Transform fn_sig inputs and output + ty = transform_ty(tcx, fn_ptr, parents, options); } ty::Ref(region, ty0, ..) => { - if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if ty.is_mutable_ptr() { - ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); - } else { - ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); - } + // Remove references from function items, closures, Fn trait and Fn subtrait objects + if ty0.is_fn_def() + || ty0.is_closure() + || is_dynamic_fn_trait(tcx, *ty0) + || is_dynamic_fn_subtrait(tcx, *ty0) + { + ty = transform_ty(tcx, *ty0, parents, options); } else { - if ty.is_mutable_ptr() { - ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options)); + if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if ty.is_mutable_ptr() { + ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); + } else { + ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); + } } else { - ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options)); + if ty.is_mutable_ptr() { + ty = Ty::new_mut_ref( + tcx, + *region, + transform_ty(tcx, *ty0, parents, options), + ); + } else { + ty = Ty::new_imm_ref( + tcx, + *region, + transform_ty(tcx, *ty0, parents, options), + ); + } } } } @@ -994,12 +1218,23 @@ fn transform_ty<'tcx>( } ty::Dynamic(predicates, _region, kind) => { - ty = Ty::new_dynamic( - tcx, - transform_predicates(tcx, predicates), - tcx.lifetimes.re_erased, - *kind, - ); + if is_fn_trait(tcx, predicates) || is_fn_subtrait(tcx, predicates) { + // Transform Fn trait and subtrait objects into function pointers + let fn_sig = ty::Binder::bind_with_vars( + fn_trait_sig(tcx, predicates).unwrap(), + List::empty(), + ); + let fn_ptr = Ty::new_fn_ptr(tcx, fn_sig); + // Transform fn_sig inputs and output + ty = transform_ty(tcx, fn_ptr, parents, options); + } else { + ty = Ty::new_dynamic( + tcx, + transform_predicates(tcx, predicates, options), + tcx.lifetimes.re_erased, + *kind, + ); + } } ty::Alias(..) => { @@ -1011,7 +1246,11 @@ fn transform_ty<'tcx>( ); } - ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { + ty::Bound(..) + | ty::CoroutineWitness(..) + | ty::Error(..) + | ty::Infer(..) + | ty::Placeholder(..) => { bug!("transform_ty: unexpected `{:?}`", ty.kind()); } } @@ -1112,7 +1351,65 @@ pub fn typeid_for_instance<'tcx>( mut instance: Instance<'tcx>, options: TypeIdOptions, ) -> String { - if matches!(instance.def, ty::InstanceDef::Virtual(..)) { + if (matches!(instance.def, ty::InstanceDef::Item(..) | ty::InstanceDef::Virtual(..)) + && tcx.is_closure_like(instance.def_id())) + || matches!( + instance.def, + ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ClosureOnceShim { .. } + ) + { + // typeid_for_fnabi is called at two locations, initially when declaring/defining functions + // and methods, which it has a lot more context/information, and later during code + // generation at call sites, which it has a lot less contex/information (i.e., after type + // erasure). + // + // In the first call (i.e., when declaring/defining functions and methods), it encodes a + // given FnAbi or Instance and assigns one or more type ids to a function or method. (These + // type ids are used later by the LowerTypeTests LLVM pass to aggregate functions/function + // pointers in groups derived from these type ids.) + // + // In the second call (i.e., during code generation), it encodes a given FnAbi or Instance + // after type erasure, and uses this type id to test if the given function/function pointer + // is member of the group derived from this type id. It means that in the first call to + // typeid_for_fnabi (where it assign type ids), it can only include at most as much + // information that would be available during code generation at call sites; otherwise, the + // type ids will not match. + // + // For this, it: + // + // * Adjusts the type ids of VTableShims to the type id expected in the call sites for the + // entry in the vtable (i.e., the signature of the closure passed as an argument to the + // shim). + // * Adjusts the type ids of ClosureOnceShims to the type id expected in the call sites for + // the entry in the vtable (i.e., the signature of the closure passed as an argument to + // the shim). + // + // And for compatibility between types, it uses their least common denominator and: + // + // * Transforms closure FnAbis into funtion pointer FnAbis. + // * Transforms Fn trait and Fn subtrait FnAbis into function pointer FnAbis. + // + let fn_abi = tcx + .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) + .unwrap_or_else(|instance| { + bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance) + }); + // Transform closure FnAbis into funtion pointer FnAbis. + let fn_abi = transform_closure_fnabi(tcx, fn_abi, options); + return typeid_for_fnabi(tcx, &fn_abi, options); + } else if matches!(instance.def, ty::InstanceDef::Virtual(..)) + && (is_dynamic_fn_trait(tcx, instance.args.type_at(0)) + || is_dynamic_fn_subtrait(tcx, instance.args.type_at(0))) + { + let fn_abi = tcx + .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) + .unwrap_or_else(|instance| { + bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance) + }); + // Transform Fn trait and Fn subtrait FnAbis into function pointer FnAbis. + let fn_abi = transform_fn_trait_fnabi(tcx, fn_abi, options); + return typeid_for_fnabi(tcx, &fn_abi, options); + } else if matches!(instance.def, ty::InstanceDef::Virtual(..)) { instance.args = strip_receiver_auto(tcx, instance.args) } diff --git a/tests/codegen/sanitizer/cfi/cfi-emit-type-metadata-id-itanium-cxx-abi-closures.rs b/tests/codegen/sanitizer/cfi/cfi-emit-type-metadata-id-itanium-cxx-abi-closures.rs new file mode 100644 index 0000000000000..56d99b166a0de --- /dev/null +++ b/tests/codegen/sanitizer/cfi/cfi-emit-type-metadata-id-itanium-cxx-abi-closures.rs @@ -0,0 +1,55 @@ +// Verifies that type metadata identifiers for closures are emitted correctly. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 + +#![crate_type="lib"] +pub fn foo1(a: fn(i32) -> i32) { + // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"[[TYPE1B:_ZTSFu3i32S_E]]") + a(1); +} + +pub fn bar1() { + foo1(|a| -> i32 { a + 1 }); + // CHECK-LABEL: define{{.*}}4bar1{{.*}}$u7b$$u7b$closure$u7d$$u7d + // CHECK-SAME: {{.*}}!type ![[TYPE1A:[[:print:]]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + fn a(a: i32) -> i32 { a + 1 } + foo1(a); + // CHECK-LABEL: define{{.*}}4bar11a + // CHECK-SAME: {{.*}}!type ![[TYPE1A:[[:print:]]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +} + +pub fn foo2(a: &dyn Fn(i32) -> i32) { + // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"[[TYPE1B]]") + a(1); +} + +pub fn bar2() { + foo2(&|a: i32| -> i32 { a + 1 }); + // CHECK-LABEL: define{{.*}}4bar2{{.*}}$u7b$$u7b$closure$u7d$$u7d + // CHECK-SAME: {{.*}}!type ![[TYPE1A:[[:print:]]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + fn a(a: i32) -> i32 { a + 1 } + foo2(&a); + // CHECK-LABEL: define{{.*}}4bar21a + // CHECK-SAME: {{.*}}!type ![[TYPE1A:[[:print:]]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +} + +pub fn foo3(a: &mut dyn FnMut(i32) -> i32) { + // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"[[TYPE1B]]") + a(1); +} + +pub fn bar3() { + foo3(&mut |a: i32| -> i32 { a + 1 }); + // CHECK-LABEL: define{{.*}}4bar3{{.*}}$u7b$$u7b$closure$u7d$$u7d + // CHECK-SAME: {{.*}}!type ![[TYPE1A:[[:print:]]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + fn a(a: i32) -> i32 { a + 1 } + foo3(&mut a); + // CHECK-LABEL: define{{.*}}4bar31a + // CHECK-SAME: {{.*}}!type ![[TYPE1A:[[:print:]]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +} + +// CHECK: ![[TYPE1A]] = !{i64 0, !"[[TYPE1B]]"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-closure-decl-def-vs-call.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-closure-decl-def-vs-call.rs new file mode 100644 index 0000000000000..24a985e847503 --- /dev/null +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-closure-decl-def-vs-call.rs @@ -0,0 +1,17 @@ +// Verifies that type metadata identifiers for closure declaration/definition FnAbis are +// disambiguated from closure call FnAbis. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type="lib"] + +pub fn foo(f: fn()) { + // CHECK-LABEL: define{{.*}}3foo + // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvvE") + f(); +} + + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFvvEE"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-fn-trait-decl-def-vs-call.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-fn-trait-decl-def-vs-call.rs new file mode 100644 index 0000000000000..0eff39d8e4281 --- /dev/null +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-fn-trait-decl-def-vs-call.rs @@ -0,0 +1,17 @@ +// Verifies that type metadata identifiers for dynamic Fn trait declaration/definition FnAbis are +// disambiguated from dynamic Fn trait call FnAbis. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type="lib"] + +pub fn foo(f: &dyn Fn()) { + // CHECK-LABEL: define{{.*}}3foo + // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvvE") + f(); +} + + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFvvEE"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs index ab3d339989b38..240e9959e3c8b 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs @@ -6,6 +6,8 @@ #![crate_type="lib"] +trait FnSubtrait: Fn() {} + pub fn foo1(_: fn(i32) -> i32) { } // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo2(_: fn(i32) -> i32, _: fn(i32) -> i32) { } @@ -13,33 +15,33 @@ pub fn foo2(_: fn(i32) -> i32, _: fn(i32) -> i32) { } pub fn foo3(_: fn(i32) -> i32, _: fn(i32) -> i32, _: fn(i32) -> i32) { } // CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo4(_: &dyn Fn(i32) -> i32) { } -// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo5(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { } -// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE2]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo6(_: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32, _: &dyn Fn(i32) -> i32) { } -// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE3]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo7(_: &dyn FnMut(i32) -> i32) { } -// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo8(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { } -// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE2]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo9(_: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32, _: &dyn FnMut(i32) -> i32) { } -// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE3]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo10(_: &dyn FnOnce(i32) -> i32) { } -// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo11(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) { } -// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE2]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo12(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32) {} -// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE3]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo13(_: &dyn FnSubtrait) { } +// CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo14(_: &dyn FnSubtrait, _: &dyn FnSubtrait) { } +// CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo15(_: &dyn FnSubtrait, _: &dyn FnSubtrait, _: &dyn FnSubtrait) {} +// CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} // CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_S3_E"} +// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvPFvvEE"} +// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvPFvvES_E"} +// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvPFvvES_S_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs index ca781a99296be..79f75af4e68cd 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -74,15 +74,15 @@ pub fn foo11(_: &Type4, _: &Type4) { } pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { } // CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFvvEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFvvES_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFvvES_S_E"} // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"} // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"} // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"} // CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"} // CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"} // CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooEEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooEES1_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooEES1_S1_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs index cc7178e41c716..c3ff5062e5c5a 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs @@ -136,16 +136,15 @@ pub fn foo27(_: &dyn Trait5, _: &dyn Trait5, _: &dyn Trait // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} // CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} -// FIXME(rcvalle): Enforce autotraits ordering when encoding (e.g., alphabetical order) -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES3_S3_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Syncu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Syncu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Syncu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_S3_E"} // CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} // CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_E"} // CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES3_S3_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_S4_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Syncu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Syncu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES4_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Syncu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES4_S4_E"} // CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_E"} // CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_S2_E"} // CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu5paramEu6regionEES3_E"} diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs index a46a3afd7343a..caad3094d5a47 100644 --- a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs +++ b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs @@ -1,18 +1,10 @@ -// Tests that converting a closure to a function pointer works -// The notable thing being tested here is that when the closure does not capture anything, -// the call method from its Fn trait takes a ZST representing its environment. The compiler then -// uses the assumption that the ZST is non-passed to reify this into a function pointer. +// Verifies that casting a closure to a function pointer works. // -// This checks that the reified function pointer will have the expected alias set at its call-site. - //@ needs-sanitizer-cfi -// FIXME(#122848) Remove only-linux once OSX CFI binaries work -//@ only-linux -//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi -//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ compile-flags: -Clto -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 //@ run-pass -pub fn main() { +fn main() { let f: &fn() = &((|| ()) as _); f(); } diff --git a/tests/ui/sanitizer/cfi-closure-fn-trait-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-trait-cast.rs new file mode 100644 index 0000000000000..d78d74cb9d5ec --- /dev/null +++ b/tests/ui/sanitizer/cfi-closure-fn-trait-cast.rs @@ -0,0 +1,13 @@ +// Verifies that casting a closure to a Fn trait object works. +// +// FIXME(#122848): Remove only-linux when fixed. +//@ only-linux +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ run-pass + +#![feature(fn_traits)] +fn main() { + let f: &(dyn Fn()) = &(|| {}) as _; + f.call(()); +} diff --git a/tests/ui/sanitizer/cfi-dynamic-fn-subtrait-call.rs b/tests/ui/sanitizer/cfi-dynamic-fn-subtrait-call.rs new file mode 100644 index 0000000000000..f2ec8691e4af0 --- /dev/null +++ b/tests/ui/sanitizer/cfi-dynamic-fn-subtrait-call.rs @@ -0,0 +1,18 @@ +// Verifies that calling a dynamic Fn subtrait object works. +// +// FIXME(#122848): Remove only-linux when fixed. +//@ only-linux +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ run-pass + +trait FnSubtrait: Fn() {} +impl FnSubtrait for T {} + +fn call_dynamic_fn_subtrait(f: &dyn FnSubtrait) { + f(); +} + +fn main() { + call_dynamic_fn_subtrait(&|| {}); +}