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..efdadfea2f07f 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 @@ -641,20 +641,7 @@ fn encode_ty<'tcx>( } // Function types - ty::FnDef(def_id, args) - | ty::Closure(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, ..) => { + ty::FnDef(def_id, args) | ty::Coroutine(def_id, args, ..) => { // u[IE], where is , // as vendor extended type. let mut s = String::new(); @@ -735,6 +722,8 @@ fn encode_ty<'tcx>( ty::Alias(..) | ty::Bound(..) | ty::Error(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) | ty::CoroutineWitness(..) | ty::Infer(..) | ty::Placeholder(..) => { @@ -745,23 +734,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 +980,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 +1001,13 @@ fn transform_ty<'tcx>( options: TransformTyOptions, ) -> Ty<'tcx> { match ty.kind() { - ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {} + ty::Coroutine(..) + | ty::Float(..) + | ty::FnDef(..) + | ty::Str + | ty::Never + | ty::Foreign(..) + | ty::Param(..) => {} ty::Bool => { if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { @@ -914,38 +1131,50 @@ 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(_, 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::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::CoroutineClosure(_, args) => { + // Transform async closures into function pointers + let fn_ptr = args.as_coroutine_closure().signature_parts_ty(); + // 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 +1223,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 +1251,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 +1356,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(&|| {}); +}