1use std::ops::ControlFlow;
23use rustc_abi::{FieldIdx, VariantIdx};
4use rustc_hir::LangItem;
5use rustc_hir::def_id::DefId;
6use rustc_infer::traits::{
7ImplSourceUserDefinedData, Obligation, ObligationCause, ObligationCauseCode,
8};
9use rustc_middle::middle::codegen_fn_attrs::ferrocene::item_is_validated;
10use rustc_middle::span_bug;
11use rustc_middle::ty::adjustment::CustomCoerceUnsized;
12use rustc_middle::ty::{
13self, ExistentialPredicate, GenericArgsRef, Instance, PolyTraitRef, ShimKind, Ty, TyCtxt,
14TypeSuperVisitableas _, TypeVisitableas _, TypingEnv, Unnormalized,
15};
16use rustc_span::Span;
17use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext, supertraits};
18use tracing::{debug, instrument};
1920use super::UnvalidatedImplCause;
21use crate::ferrocene::{InstantiateResult, LintState, UseKind};
2223type ImplSource<'tcx> = rustc_infer::traits::ImplSource<'tcx, Span>;
2425impl<'tcx> LintState<'tcx> {
26pub(super) fn check_fn_ptr_coercion(
27&self,
28 source: Ty<'tcx>,
29 dst_trait: PolyTraitRef<'tcx>,
30 try_instantiate: &mut impl FnMut(DefId, GenericArgsRef<'tcx>) -> InstantiateResult<'tcx>,
31 span: Span,
32 ) -> Option<UseKind<'tcx>> {
33{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:33",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(33u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("check cast of {0:?} to function pointer",
source) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("check cast of {source:?} to function pointer");
34let tcx = self.tcx;
3536match self.instance_of_ty(source, Some(dst_trait), try_instantiate, span) {
37Some(instance) => {
38if #[allow(non_exhaustive_omitted_patterns)] match instance.def {
ty::InstanceKind::Virtual(..) => true,
_ => false,
}matches!(instance.def, ty::InstanceKind::Virtual(..)) {
39// This is a `<dyn Trait>::method as fn()` cast.
40 // That shim is synthesized and therefore covered under the compiler
41 // qualification. It can't be called unless someone gets a `dyn Trait`, in which
42 // case we'll lint the unsizing cast.
43None44 } else if item_is_validated(tcx, instance.def_id()).validated() {
45None46 } else {
47Some(UseKind::FnPtrCast(instance))
48 }
49 }
50// Uncaught fn pointer casts are ok because the post-mono pass will check them later.
51 // FIXME: this is messy, split this out into `check_dyn_trait_coercion`
52Noneif Some(dst_trait.def_id()) == tcx.lang_items().fn_ptr_trait() => None,
53// FIXME: feature(unboxed_closures)
54Noneif source.is_adt() => None,
55// Don't remove this panic. If you do so before adding `check_dyn_trait_coercion` to
56 // the post-mono pass, it will fail to catch real uses of unvalidated items in
57 // non-degenerate programs.
58None => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("unimplemented: pre-mono cast from {0} to dyn {1}() that fails to instantiate",
source, dst_trait))span_bug!(
59 span,
60"unimplemented: pre-mono cast from {source} to dyn {dst_trait}() that fails to instantiate"
61),
62 }
63 }
6465/// Given a `source` expression that has an unsizing cast to `dest`, determine
66 /// whether the cast is valid. If not, return a [`TraitObjectCast`](UseKind::TraitObjectCast) showing why not.
67 ///
68 /// This works in four main parts:
69 /// 1. "Peel" as many types as possible. For example, if we are casting `Vec<Box<String>>` to
70 /// `Vec<Box<dyn Display + Clone + Sync>`, peel that to `String` and
71 /// `dyn Display + Clone + Sync`. We call these `coerce_src` and `coerce_dst`.
72 /// 2. Determine all traits in `dest`'s type that have at least one method. For example,
73 /// `dyn Display + Clone + Sync` contains the traits `Display` and `Clone`.
74 /// 3. For each trait, find `coerce_src`'s implementation of it. For example,
75 /// `impl Display for String`.
76 /// 4. For each method in the impl, check whether it's validated. For example, we would check
77 /// `<String as Diplay>::fmt`, see that it's unvalidated, and return its `DefId` in the
78 /// `UseKind`.
79x;#[instrument(skip(self, try_instantiate, span), ret)]80pub(super) fn check_dyn_trait_coercion(
81&self,
82 dest_ty: Ty<'tcx>,
83 source_ty: Ty<'tcx>,
84 typing_env: TypingEnv<'tcx>,
85 try_instantiate: &mut impl FnMut(DefId, GenericArgsRef<'tcx>) -> InstantiateResult<'tcx>,
86 span: Span,
87 ) -> Option<UseKind<'tcx>> {
88let tcx = self.tcx;
8990let (coerce_src, coerce_dst) =
91self.peel_unsized_tys(source_ty, dest_ty, typing_env, span)?;
92debug!(
93"saw unsized coercion from {source_ty:?} -> {dest_ty:?} (peeled: {coerce_src:?} -> {coerce_dst:?})",
94 );
9596if matches!(coerce_src.kind(), ty::Dynamic(..) | ty::FnPtr(..)) {
97// upcasting from a `dyn Trait` to a `dyn SuperTrait`.
98 // We already checked this when we originally cast to `dyn Trait`.
99return None;
100 }
101102let bound_traits = self.dyn_trait_refs(coerce_src, coerce_dst);
103// NOTE: this only checks functions directly on the `trait_ref`.
104 // Supertraits are already handled in `dyn_trait_refs` as a separate trait.
105for trait_ref in bound_traits {
106// First, check if we are casting to a `dyn Fn*` trait.
107 // If so, this is disallowed no matter what, for the same reason as casting
108 // to a function pointer.
109if tcx.fn_trait_kind_from_def_id(trait_ref.def_id()).is_some() {
110if let Some(use_) =
111self.check_fn_ptr_coercion(coerce_src, trait_ref, try_instantiate, span)
112 {
113return Some(use_);
114 } else {
115continue;
116 }
117 }
118119if tcx
120 .associated_item_def_ids(trait_ref.def_id())
121 .iter()
122 .find(|&id| tcx.def_kind(*id).is_fn_like())
123 .is_none()
124 {
125// not possible to call any functions on this trait object, casting is always ok.
126continue;
127 };
128let impl_ = self.find_trait_impl(trait_ref, typing_env, span);
129130match impl_ {
131 ImplSource::UserDefined(ImplSourceUserDefinedData {
132 impl_def_id,
133 args: _,
134 nested: _,
135 }) => {
136// This function in the impl needs to be marked with `prevalidated`.
137if let Some(impl_fn) = self.find_unvalidated_impl_fn(impl_def_id) {
138return Some(UseKind::TraitObjectCast(
139 UnvalidatedImplCause::AssocFn(impl_fn),
140 coerce_src,
141 ));
142 }
143 }
144// builtin impls are always ok
145ImplSource::Builtin(..) => continue,
146 ImplSource::Param(_obligations) => {
147// This is something like the following:
148 // ```
149 // fn foo<T: Display + 'static>(x: T) -> Box<dyn Display> {
150 // Box::new(x)
151 // }
152 // ```
153 // We can't resolve `x.fmt` until post-mono, so we can't point to the reason
154 // the cast is disallowed.
155156 // NOTE: this can give an empty list of obligations in weird cases like
157 // `core::mem::DiscriminantKind`, which is automatically implemented for any Sized type.
158return Some(UseKind::TraitObjectCast(
159 UnvalidatedImplCause::UnresolvedGenericImpl(trait_ref),
160 coerce_src,
161 ));
162 }
163 }
164 }
165None
166}
167168/// Given a call to a function-like type, return the instantiated function definition,
169 /// or `None` if we can't find it until it's been monomorphized.
170 ///
171 /// Panics if given a type that isn't callable.
172pub(super) fn instance_of_ty(
173&self,
174 ty: Ty<'tcx>,
175 fn_trait_ref: Option<PolyTraitRef<'tcx>>,
176 try_instantiate: &mut impl FnMut(DefId, GenericArgsRef<'tcx>) -> InstantiateResult<'tcx>,
177 span: Span,
178 ) -> Option<Instance<'tcx>> {
179let tcx = self.tcx;
180181match ty.kind() {
182 ty::FnDef(maybe_trait_fn, generic_args) => {
183// Indeterminate results are handled later by a post-mono pass that checks the
184 // instantiation is validated. For now just ignore errors.
185try_instantiate(*maybe_trait_fn, generic_args.no_bound_vars().unwrap()).instance()
186 }
187 ty::Closure(def_id, args) => {
188Some(Instance::resolve_closure(tcx, *def_id, args, ty::ClosureKind::FnOnce))
189 }
190 ty::CoroutineClosure(def_id, args) => {
191let coroutine_closure_def_id = *def_id;
192// See comment in `rustc_ty_utils::instance::resolve_associated_item`.
193let instance = if ty::ClosureKind::FnOnce == args.as_coroutine_closure().kind() {
194Instance::new_raw(coroutine_closure_def_id, args)
195 } else {
196let trait_id = fn_trait_ref.unwrap().def_id();
197let target_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
198Instance {
199 def: ty::InstanceKind::Shim(ShimKind::ConstructCoroutineInClosure {
200coroutine_closure_def_id,
201 receiver_by_ref: target_kind != ty::ClosureKind::FnOnce,
202 }),
203args,
204 }
205 };
206Some(instance)
207 }
208// FIXME: `feature(unboxed_closures)`.
209 // Right now we just ignore `fn_trait_ref`, but it's passed in here so that we can call
210 // `find_trait_impl(fn_trait_ref.with_self_ty(ty)`.
211ty::Adt(..) => None,
212// Reference to a function or function pointer.
213ty::Ref(_, ty, _) => self.instance_of_ty(*ty, fn_trait_ref, try_instantiate, span),
214// We assume that all functions pointers are valid. Proof:
215 // 1. If the function was validated, no problem.
216 // 2. If the function was unvalidated, and is a literal or assigned to a local
217 // variable, then either:
218 // - We can resolve it to a concrete instance, in which case we would have caught it in `ZstLiteral` above.
219 // - We can't resolve it yet, but it stays a unique function type, so we will
220 // catch the call later in the post-mono pass.
221 // - We can't resolve it yet and it's cast to a function pointer so we don't
222 // have enough info to catch it post-mono when it's called. In this case we
223 // catch it in `ReifyFnPtr` above.
224 // 3. If the function was passed as an argument, then either:
225 // - We were called by an unvalidated function. No problem.
226 // - We were called by a validated function. This lint will run on that
227 // function too, and we will catch it there at the time it is checked /
228 // monomorphized.
229 // 4. If this is a closure then either:
230 // - It was defined in this function, in which case we treat it as also
231 // validated.
232 // - It was passed as an argument, which is ok by 3).
233 // - It is a global const/static, so we catch it in `NamedConst`/`StaticRef` above.
234ty::FnPtr(..) => None,
235 other => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("unsupported call kind {0:?}", other))span_bug!(span, "unsupported call kind {other:?}"),
236 }
237 }
238239/// Given an `Unsize` coersion from `src_ty` to `dst_ty`, return the innermost "difference"
240 /// between the two. Returns `None` if this isn't a cast to a trait object.
241 ///
242 /// This is quite similar to `struct_lockstep_tails_for_codegen`, except it considers all ZSTs,
243 /// not just those at the tail.
244 ///
245 /// c.f. [Zulip](https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/Get.20a.20type's.20impl.20for.20a.20trait/with/570837962)
246 ///
247 /// See [`CoerceUnsized`](https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html) for a full
248 /// list of types we need to handle here.
249 ///
250 /// This is adapted from `rustc_monomorphize::collector::find_tails_for_unsizing`.
251fn peel_unsized_tys(
252&self,
253 src_ty: Ty<'tcx>,
254 dst_ty: Ty<'tcx>,
255 typing_env: TypingEnv<'tcx>,
256 span: Span,
257 ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
258{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:258",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(258u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("unsize_ptr: {0:?} => {1:?}",
src_ty, dst_ty) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
259260let tcx = self.tcx;
261let (mut src_inner, mut dst_inner) = (src_ty, dst_ty);
262263let get_adt_field = |adt_def: ty::AdtDef<'_>, args, idx: FieldIdx| {
264let variant = adt_def.variant(VariantIdx::ZERO);
265let field_ty = variant.fields[idx].ty(tcx, args).skip_norm_wip();
266tcx.normalize_erasing_regions(typing_env, Unnormalized::new(field_ty))
267 };
268269loop {
270{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:270",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(270u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("peel_tys step: src={0:?}, dst={1:?}",
src_inner, dst_inner) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("peel_tys step: src={src_inner:?}, dst={dst_inner:?}");
271match (src_inner.kind(), dst_inner.kind()) {
272/* End conditions. */
273(_, ty::Dynamic(..)) => return Some((src_inner, dst_inner)),
274// There's only ever one unsizing coercion at once.
275 // Even if this is a `[dyn Trait; N]`, we would have checked it earlier.
276 // Return now so we don't crash trying to prove that the array implements `Trait`.
277(ty::Array(..), ty::Slice(..)) => return None,
278279/* We've finished handling CoerceUnsized; now handle Unsize.
280 * From here onward, the only thing we'll ever hit in the loop is `Dynamic` or
281 * `Array` (handled above). */
282(ty::Ref(_, a, _), ty::Ref(_, b, _)) | (ty::RawPtr(a, _), ty::RawPtr(b, _)) => {
283 (src_inner, dst_inner) =
284tcx.struct_lockstep_tails_for_codegen(*a, *b, typing_env);
285 }
286287/* Handle CoerceUnsized.
288 * This is the only part of the loop that recurses more than once. */
289(ty::Pat(a, _), ty::Pat(b, _)) => {
290 (src_inner, dst_inner) = (*a, *b);
291 }
292293 (ty::Adt(src_def, src_args), ty::Adt(dst_def, dst_args)) => {
294{
match (&src_def.did(), &dst_def.did()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(src_def.did(), dst_def.did());
295296if let Some(boxed) = src_inner.boxed_ty() {
297src_inner = boxed;
298dst_inner = dst_inner.boxed_ty().unwrap();
299continue;
300 }
301302let field = match self.custom_coerce_unsize_info(src_inner, dst_inner, span) {
303Some(CustomCoerceUnsized::Struct(idx)) => idx,
304None => {
305// Iterate this struct looking for a `!Sized` field.
306let mut unsized_field = None;
307for (idx, def) in
308dst_def.variant(VariantIdx::ZERO).fields.iter_enumerated()
309 {
310if !def.ty(tcx, dst_args).skip_norm_wip().is_sized(tcx, typing_env)
311 {
312 unsized_field = Some(idx);
313break;
314 }
315 }
316unsized_field.unwrap_or_else(|| {
317::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("Adt with no CoerceUnsized impl and no !Sized field? {0:?}",
dst_inner));span_bug!(span, "Adt with no CoerceUnsized impl and no !Sized field? {dst_inner:?}");
318 })
319 }
320 };
321src_inner = get_adt_field(*src_def, src_args, field);
322dst_inner = get_adt_field(*dst_def, dst_args, field);
323 }
324_ => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("mismatched types trying to coerce from {0:?} to {1:?}",
src_ty, dst_ty))span_bug!(
325 span,
326"mismatched types trying to coerce from {src_ty:?} to {dst_ty:?}"
327),
328 }
329 }
330 }
331332// copied from rustc_monomorphize
333fn custom_coerce_unsize_info(
334&self,
335 source_ty: Ty<'tcx>,
336 target_ty: Ty<'tcx>,
337 span: Span,
338 ) -> Option<CustomCoerceUnsized> {
339let tcx = self.tcx;
340let trait_ref = ty::TraitRef::new(
341tcx,
342tcx.require_lang_item(LangItem::CoerceUnsized, span),
343 [source_ty, target_ty],
344 );
345346match tcx.codegen_select_candidate(
347 ty::TypingEnv::fully_monomorphized().as_query_input(trait_ref),
348 ) {
349Ok(rustc_infer::traits::ImplSource::UserDefined(ImplSourceUserDefinedData {
350 impl_def_id,
351 ..
352 })) => Some(tcx.coerce_unsized_info(*impl_def_id).unwrap().custom_kind.unwrap()),
353_ => None,
354 }
355 }
356357/// Given an `impl`, find the first associated function that isn't validated.
358 ///
359 /// FIXME: list all unvalidated functions, not just the first.
360fn find_unvalidated_impl_fn(&self, impl_block: DefId) -> Option<DefId> {
361let tcx = self.tcx;
362363let trait_to_impl_map = tcx.impl_item_implementor_ids(impl_block);
364for trait_item in tcx.associated_item_def_ids(tcx.impl_trait_id(impl_block)) {
365{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:365",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(365u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("considering {0:?}",
trait_item) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("considering {trait_item:?}");
366if !tcx.def_kind(*trait_item).is_fn_like() {
367{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:367",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(367u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("ignoring non-fn {0:?}",
trait_item) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("ignoring non-fn {trait_item:?}");
368continue;
369 }
370371// Need this map so we consider default trait fns even if they're not mentioned in the
372 // impl block.
373let impl_fn = *trait_to_impl_map.get(trait_item).unwrap_or(trait_item);
374375if item_is_validated(tcx, impl_fn).validated() {
376continue;
377 }
378379{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:379",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(379u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("found unvalidated method {0:?}",
impl_fn) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("found unvalidated method {impl_fn:?}");
380// This function in the impl needs to be marked with `prevalidated`.
381return Some(impl_fn);
382 }
383return None;
384 }
385386fn find_trait_impl(
387&self,
388 trait_ref: PolyTraitRef<'tcx>,
389 typing_env: TypingEnv<'tcx>,
390 span: Span,
391 ) -> ImplSource<'tcx> {
392match self.try_find_trait_impl(trait_ref, typing_env, span) {
393Some(found) => found,
394None => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("failed to resolve impl: {0:?}", trait_ref))span_bug!(span, "failed to resolve impl: {trait_ref:?}"),
395 }
396 }
397398/// Given a `Trait<Ty>` reference, find `impl Trait for Ty`.
399 ///
400 /// This calls into the [trait solver] to select a suitable impl block.
401 ///
402 /// c.f. [`hax::exporter::traits::resolution::shallow_resolve_trait_ref`](https://github.com/AeneasVerif/hax/blob/3c2b6f01af4a4362dd855b811aa910ad173d546f/frontend/exporter/src/traits/resolution.rs#L666)
403 ///
404 /// Ideally, this would never return None, but sometimes our code is buggy ... failures here
405 /// only degrade the diagnostic, they don't cause soundness issues.
406 ///
407 /// [trait solver]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
408fn try_find_trait_impl(
409&self,
410 trait_ref: PolyTraitRef<'tcx>,
411 typing_env: TypingEnv<'tcx>,
412 span: Span,
413 ) -> Option<ImplSource<'tcx>> {
414use rustc_infer::infer::TyCtxtInferExt;
415416let tcx = self.tcx;
417let (infcx, param_env) =
418tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env);
419{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:419",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(419u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("resolving impl for {0:?}",
trait_ref) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("resolving impl for {trait_ref:?}");
420421// Find the impl block.
422let mut selcx = SelectionContext::new(&infcx);
423let cause = ObligationCause::new(span, self.item, ObligationCauseCode::ExprAssignable);
424// Normalize the trait ref.
425let trait_ref = tcx.normalize_erasing_regions(typing_env, Unnormalized::new(trait_ref));
426// method selection doesn't care about regions.
427let trait_ref = tcx.instantiate_bound_regions_with_erased(trait_ref);
428let obligation = Obligation::new(tcx, cause, param_env, trait_ref);
429let selection = match selcx.select(&obligation) {
430Ok(selection) => selection?,
431Err(e) => {
432{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:432",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(432u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("type checking failed for trait upcast? {0:?}",
e) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("type checking failed for trait upcast? {e:?}");
433return None;
434 }
435 };
436{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:436",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(436u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("selected {0:?}",
selection) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("selected {selection:?}");
437438// Sanity check: make sure all `where` clauses on our `impl` are upheld.
439let ocx = ObligationCtxt::new(&infcx);
440let impl_source = selection.map(|o| {
441{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:441",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(441u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("registering obligation {0:?}",
o) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("registering obligation {o:?}");
442let span = o.cause.span;
443ocx.register_obligation(o);
444span445 });
446let errors = ocx.evaluate_obligations_error_on_ambiguity();
447if !errors.is_empty() {
448{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:448",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(448u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("impl obligations not met for trait upcast: {0:?}",
errors) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("impl obligations not met for trait upcast: {errors:?}");
449return None;
450 }
451452let normalized_impl =
453tcx.erase_and_anonymize_regions(infcx.resolve_vars_if_possible(impl_source));
454{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:454",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(454u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("found impl {0:?}",
normalized_impl) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("found impl {normalized_impl:?}");
455Some(normalized_impl)
456 }
457458/// Given a Rust type, find (at any level of nesting) `dyn Trait` objects contained within it that
459 /// have at least one method.
460 /// For example, `dyn Send + Sync + Display + Clone` would return `[Display, Clone]`.
461fn dyn_trait_refs(
462&self,
463 source_ty: Ty<'tcx>,
464 dst_ty: Ty<'tcx>,
465 ) -> Vec<ty::Binder<'tcx, ty::TraitRef<'tcx>>> {
466struct FindDynTraitVisitor<'tcx>(TyCtxt<'tcx>, Ty<'tcx>);
467468impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FindDynTraitVisitor<'tcx> {
469type Result = ControlFlow<Vec<ty::Binder<'tcx, ty::TraitRef<'tcx>>>>;
470471fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
472match t.kind() {
473 ty::Dynamic(bound_predicates, _lifetime) => {
474let mut traits = ::alloc::vec::Vec::new()vec![];
475for predicate in *bound_predicates {
476{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/ferrocene/dynamic_casts.rs:476",
"rustc_lint::ferrocene::dynamic_casts",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/dynamic_casts.rs"),
::tracing_core::__macro_support::Option::Some(476u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::dynamic_casts"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("considering {0:?}",
predicate) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("considering {predicate:?}");
477let trait_ = predicate
478 .map_bound(|p| match p {
479// auto traits do not allow calling methods
480ExistentialPredicate::AutoTrait(_) => None,
481// We don't care about associated type bounds.
482 // They restrict which impl is selected, but that's all they do.
483 // We already require the implementation of the trait to be validated
484 // (that's the `Trait` predicate below), so which impl gets picked
485 // doesn't matter as long we know which one it is.
486ExistentialPredicate::Projection(_) => None,
487 ExistentialPredicate::Trait(t) => Some(t),
488 })
489 .transpose();
490if let Some(t) = trait_ {
491let t = t.with_self_ty(self.0, self.1);
492 traits.push(t);
493 traits.extend(supertraits(self.0, t));
494 }
495 }
496// FIXME: is it possible to have multiple Dynamic types in a single top-level
497 // type? how? maybe with an enum?
498ControlFlow::Break(traits)
499 }
500_ => t.super_visit_with(self),
501 }
502 }
503 }
504505let cf = dst_ty.visit_with(&mut FindDynTraitVisitor(self.tcx, source_ty));
506cf.break_value().unwrap_or_default()
507 }
508}