1 //! "Object safety" refers to the ability for a trait to be converted
2 //! to an object. In general, traits may only be converted to an
3 //! object if all of their methods meet certain criteria. In particular,
4 //! they must:
5 //!
6 //! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version
7 //! that doesn't contain the vtable;
8 //! - not reference the erased type `Self` except for in this receiver;
9 //! - not have generic type parameters.
10
11 use super::elaborate;
12
13 use crate::infer::TyCtxtInferExt;
14 use crate::traits::query::evaluate_obligation::InferCtxtExt;
15 use crate::traits::{self, Obligation, ObligationCause};
16 use rustc_errors::{DelayDm, FatalError, MultiSpan};
17 use rustc_hir as hir;
18 use rustc_hir::def_id::DefId;
19 use rustc_middle::query::Providers;
20 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
21 use rustc_middle::ty::{
22 self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
23 };
24 use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
25 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
26 use rustc_span::symbol::Symbol;
27 use rustc_span::Span;
28 use smallvec::SmallVec;
29
30 use std::iter;
31 use std::ops::ControlFlow;
32
33 pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
34
35 /// Returns the object safety violations that affect
36 /// astconv -- currently, `Self` in supertraits. This is needed
37 /// because `object_safety_violations` can't be used during
38 /// type collection.
astconv_object_safety_violations( tcx: TyCtxt<'_>, trait_def_id: DefId, ) -> Vec<ObjectSafetyViolation>39 pub fn astconv_object_safety_violations(
40 tcx: TyCtxt<'_>,
41 trait_def_id: DefId,
42 ) -> Vec<ObjectSafetyViolation> {
43 debug_assert!(tcx.generics_of(trait_def_id).has_self);
44 let violations = traits::supertrait_def_ids(tcx, trait_def_id)
45 .map(|def_id| predicates_reference_self(tcx, def_id, true))
46 .filter(|spans| !spans.is_empty())
47 .map(ObjectSafetyViolation::SupertraitSelf)
48 .collect();
49
50 debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations);
51
52 violations
53 }
54
object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [ObjectSafetyViolation]55 fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [ObjectSafetyViolation] {
56 debug_assert!(tcx.generics_of(trait_def_id).has_self);
57 debug!("object_safety_violations: {:?}", trait_def_id);
58
59 tcx.arena.alloc_from_iter(
60 traits::supertrait_def_ids(tcx, trait_def_id)
61 .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)),
62 )
63 }
64
check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool65 fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
66 let violations = tcx.object_safety_violations(trait_def_id);
67
68 if violations.is_empty() {
69 return true;
70 }
71
72 // If the trait contains any other violations, then let the error reporting path
73 // report it instead of emitting a warning here.
74 if violations.iter().all(|violation| {
75 matches!(
76 violation,
77 ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _)
78 )
79 }) {
80 for violation in violations {
81 if let ObjectSafetyViolation::Method(
82 _,
83 MethodViolationCode::WhereClauseReferencesSelf,
84 span,
85 ) = violation
86 {
87 lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
88 }
89 }
90 return true;
91 }
92
93 false
94 }
95
96 /// We say a method is *vtable safe* if it can be invoked on a trait
97 /// object. Note that object-safe traits can have some
98 /// non-vtable-safe methods, so long as they require `Self: Sized` or
99 /// otherwise ensure that they cannot be used when `Self = Trait`.
is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool100 pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
101 debug_assert!(tcx.generics_of(trait_def_id).has_self);
102 debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
103 // Any method that has a `Self: Sized` bound cannot be called.
104 if tcx.generics_require_sized_self(method.def_id) {
105 return false;
106 }
107
108 match virtual_call_violation_for_method(tcx, trait_def_id, method) {
109 None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
110 Some(_) => false,
111 }
112 }
113
object_safety_violations_for_trait( tcx: TyCtxt<'_>, trait_def_id: DefId, ) -> Vec<ObjectSafetyViolation>114 fn object_safety_violations_for_trait(
115 tcx: TyCtxt<'_>,
116 trait_def_id: DefId,
117 ) -> Vec<ObjectSafetyViolation> {
118 // Check assoc items for violations.
119 let mut violations: Vec<_> = tcx
120 .associated_items(trait_def_id)
121 .in_definition_order()
122 .filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item))
123 .collect();
124
125 // Check the trait itself.
126 if trait_has_sized_self(tcx, trait_def_id) {
127 // We don't want to include the requirement from `Sized` itself to be `Sized` in the list.
128 let spans = get_sized_bounds(tcx, trait_def_id);
129 violations.push(ObjectSafetyViolation::SizedSelf(spans));
130 }
131 let spans = predicates_reference_self(tcx, trait_def_id, false);
132 if !spans.is_empty() {
133 violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
134 }
135 let spans = bounds_reference_self(tcx, trait_def_id);
136 if !spans.is_empty() {
137 violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
138 }
139 let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id);
140 if !spans.is_empty() {
141 violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans));
142 }
143
144 debug!(
145 "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
146 trait_def_id, violations
147 );
148
149 violations
150 }
151
152 /// Lint object-unsafe trait.
lint_object_unsafe_trait( tcx: TyCtxt<'_>, span: Span, trait_def_id: DefId, violation: &ObjectSafetyViolation, )153 fn lint_object_unsafe_trait(
154 tcx: TyCtxt<'_>,
155 span: Span,
156 trait_def_id: DefId,
157 violation: &ObjectSafetyViolation,
158 ) {
159 // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
160 // It's also hard to get a use site span, so we use the method definition span.
161 tcx.struct_span_lint_hir(
162 WHERE_CLAUSES_OBJECT_SAFETY,
163 hir::CRATE_HIR_ID,
164 span,
165 DelayDm(|| format!("the trait `{}` cannot be made into an object", tcx.def_path_str(trait_def_id))),
166 |err| {
167 let node = tcx.hir().get_if_local(trait_def_id);
168 let mut spans = MultiSpan::from_span(span);
169 if let Some(hir::Node::Item(item)) = node {
170 spans.push_span_label(
171 item.ident.span,
172 "this trait cannot be made into an object...",
173 );
174 spans.push_span_label(span, format!("...because {}", violation.error_msg()));
175 } else {
176 spans.push_span_label(
177 span,
178 format!(
179 "the trait cannot be made into an object because {}",
180 violation.error_msg()
181 ),
182 );
183 };
184 err.span_note(
185 spans,
186 "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
187 call to be resolvable dynamically; for more information visit \
188 <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
189 );
190 if node.is_some() {
191 // Only provide the help if its a local trait, otherwise it's not
192 violation.solution(err);
193 }
194 err
195 },
196 );
197 }
198
sized_trait_bound_spans<'tcx>( tcx: TyCtxt<'tcx>, bounds: hir::GenericBounds<'tcx>, ) -> impl 'tcx + Iterator<Item = Span>199 fn sized_trait_bound_spans<'tcx>(
200 tcx: TyCtxt<'tcx>,
201 bounds: hir::GenericBounds<'tcx>,
202 ) -> impl 'tcx + Iterator<Item = Span> {
203 bounds.iter().filter_map(move |b| match b {
204 hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None)
205 if trait_has_sized_self(
206 tcx,
207 trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
208 ) =>
209 {
210 // Fetch spans for supertraits that are `Sized`: `trait T: Super`
211 Some(trait_ref.span)
212 }
213 _ => None,
214 })
215 }
216
get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]>217 fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
218 tcx.hir()
219 .get_if_local(trait_def_id)
220 .and_then(|node| match node {
221 hir::Node::Item(hir::Item {
222 kind: hir::ItemKind::Trait(.., generics, bounds, _),
223 ..
224 }) => Some(
225 generics
226 .predicates
227 .iter()
228 .filter_map(|pred| {
229 match pred {
230 hir::WherePredicate::BoundPredicate(pred)
231 if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id =>
232 {
233 // Fetch spans for trait bounds that are Sized:
234 // `trait T where Self: Pred`
235 Some(sized_trait_bound_spans(tcx, pred.bounds))
236 }
237 _ => None,
238 }
239 })
240 .flatten()
241 // Fetch spans for supertraits that are `Sized`: `trait T: Super`.
242 .chain(sized_trait_bound_spans(tcx, bounds))
243 .collect::<SmallVec<[Span; 1]>>(),
244 ),
245 _ => None,
246 })
247 .unwrap_or_else(SmallVec::new)
248 }
249
predicates_reference_self( tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool, ) -> SmallVec<[Span; 1]>250 fn predicates_reference_self(
251 tcx: TyCtxt<'_>,
252 trait_def_id: DefId,
253 supertraits_only: bool,
254 ) -> SmallVec<[Span; 1]> {
255 let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
256 let predicates = if supertraits_only {
257 tcx.super_predicates_of(trait_def_id)
258 } else {
259 tcx.predicates_of(trait_def_id)
260 };
261 predicates
262 .predicates
263 .iter()
264 .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
265 .filter_map(|predicate| predicate_references_self(tcx, predicate))
266 .collect()
267 }
268
bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]>269 fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
270 tcx.associated_items(trait_def_id)
271 .in_definition_order()
272 .filter(|item| item.kind == ty::AssocKind::Type)
273 .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied())
274 .filter_map(|c| predicate_references_self(tcx, c))
275 .collect()
276 }
277
predicate_references_self<'tcx>( tcx: TyCtxt<'tcx>, (predicate, sp): (ty::Clause<'tcx>, Span), ) -> Option<Span>278 fn predicate_references_self<'tcx>(
279 tcx: TyCtxt<'tcx>,
280 (predicate, sp): (ty::Clause<'tcx>, Span),
281 ) -> Option<Span> {
282 let self_ty = tcx.types.self_param;
283 let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into());
284 match predicate.kind().skip_binder() {
285 ty::ClauseKind::Trait(ref data) => {
286 // In the case of a trait predicate, we can skip the "self" type.
287 data.trait_ref.substs[1..].iter().any(has_self_ty).then_some(sp)
288 }
289 ty::ClauseKind::Projection(ref data) => {
290 // And similarly for projections. This should be redundant with
291 // the previous check because any projection should have a
292 // matching `Trait` predicate with the same inputs, but we do
293 // the check to be safe.
294 //
295 // It's also won't be redundant if we allow type-generic associated
296 // types for trait objects.
297 //
298 // Note that we *do* allow projection *outputs* to contain
299 // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
300 // we just require the user to specify *both* outputs
301 // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
302 //
303 // This is ALT2 in issue #56288, see that for discussion of the
304 // possible alternatives.
305 data.projection_ty.substs[1..].iter().any(has_self_ty).then_some(sp)
306 }
307 ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp),
308
309 ty::ClauseKind::WellFormed(..)
310 | ty::ClauseKind::TypeOutlives(..)
311 | ty::ClauseKind::RegionOutlives(..)
312 // FIXME(generic_const_exprs): this can mention `Self`
313 | ty::ClauseKind::ConstEvaluatable(..)
314 => None,
315 }
316 }
317
super_predicates_have_non_lifetime_binders( tcx: TyCtxt<'_>, trait_def_id: DefId, ) -> SmallVec<[Span; 1]>318 fn super_predicates_have_non_lifetime_binders(
319 tcx: TyCtxt<'_>,
320 trait_def_id: DefId,
321 ) -> SmallVec<[Span; 1]> {
322 // If non_lifetime_binders is disabled, then exit early
323 if !tcx.features().non_lifetime_binders {
324 return SmallVec::new();
325 }
326 tcx.super_predicates_of(trait_def_id)
327 .predicates
328 .iter()
329 .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span))
330 .collect()
331 }
332
trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool333 fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
334 tcx.generics_require_sized_self(trait_def_id)
335 }
336
generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool337 fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
338 let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
339 return false; /* No Sized trait, can't require it! */
340 };
341
342 // Search for a predicate like `Self : Sized` amongst the trait bounds.
343 let predicates = tcx.predicates_of(def_id);
344 let predicates = predicates.instantiate_identity(tcx).predicates;
345 elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() {
346 ty::ClauseKind::Trait(ref trait_pred) => {
347 trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
348 }
349 ty::ClauseKind::RegionOutlives(_)
350 | ty::ClauseKind::TypeOutlives(_)
351 | ty::ClauseKind::Projection(_)
352 | ty::ClauseKind::ConstArgHasType(_, _)
353 | ty::ClauseKind::WellFormed(_)
354 | ty::ClauseKind::ConstEvaluatable(_) => false,
355 })
356 }
357
358 /// Returns `Some(_)` if this item makes the containing trait not object safe.
359 #[instrument(level = "debug", skip(tcx), ret)]
object_safety_violation_for_assoc_item( tcx: TyCtxt<'_>, trait_def_id: DefId, item: ty::AssocItem, ) -> Option<ObjectSafetyViolation>360 fn object_safety_violation_for_assoc_item(
361 tcx: TyCtxt<'_>,
362 trait_def_id: DefId,
363 item: ty::AssocItem,
364 ) -> Option<ObjectSafetyViolation> {
365 // Any item that has a `Self : Sized` requisite is otherwise
366 // exempt from the regulations.
367 if tcx.generics_require_sized_self(item.def_id) {
368 return None;
369 }
370
371 match item.kind {
372 // Associated consts are never object safe, as they can't have `where` bounds yet at all,
373 // and associated const bounds in trait objects aren't a thing yet either.
374 ty::AssocKind::Const => {
375 Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span))
376 }
377 ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| {
378 let node = tcx.hir().get_if_local(item.def_id);
379 // Get an accurate span depending on the violation.
380 let span = match (&v, node) {
381 (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
382 (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
383 (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
384 (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
385 node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
386 }
387 _ => item.ident(tcx).span,
388 };
389
390 ObjectSafetyViolation::Method(item.name, v, span)
391 }),
392 // Associated types can only be object safe if they have `Self: Sized` bounds.
393 ty::AssocKind::Type => {
394 if !tcx.features().generic_associated_types_extended
395 && !tcx.generics_of(item.def_id).params.is_empty()
396 && item.opt_rpitit_info.is_none()
397 {
398 Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span))
399 } else {
400 // We will permit associated types if they are explicitly mentioned in the trait object.
401 // We can't check this here, as here we only check if it is guaranteed to not be possible.
402 None
403 }
404 }
405 }
406 }
407
408 /// Returns `Some(_)` if this method cannot be called on a trait
409 /// object; this does not necessarily imply that the enclosing trait
410 /// is not object safe, because the method might have a where clause
411 /// `Self:Sized`.
virtual_call_violation_for_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: ty::AssocItem, ) -> Option<MethodViolationCode>412 fn virtual_call_violation_for_method<'tcx>(
413 tcx: TyCtxt<'tcx>,
414 trait_def_id: DefId,
415 method: ty::AssocItem,
416 ) -> Option<MethodViolationCode> {
417 let sig = tcx.fn_sig(method.def_id).subst_identity();
418
419 // The method's first parameter must be named `self`
420 if !method.fn_has_self_parameter {
421 let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
422 generics,
423 kind: hir::TraitItemKind::Fn(sig, _),
424 ..
425 })) = tcx.hir().get_if_local(method.def_id).as_ref()
426 {
427 let sm = tcx.sess.source_map();
428 Some((
429 (
430 format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }),
431 sm.span_through_char(sig.span, '(').shrink_to_hi(),
432 ),
433 (
434 format!("{} Self: Sized", generics.add_where_or_trailing_comma()),
435 generics.tail_span_for_predicate_suggestion(),
436 ),
437 ))
438 } else {
439 None
440 };
441 return Some(MethodViolationCode::StaticMethod(sugg));
442 }
443
444 for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
445 if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
446 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
447 kind: hir::TraitItemKind::Fn(sig, _),
448 ..
449 })) = tcx.hir().get_if_local(method.def_id).as_ref()
450 {
451 Some(sig.decl.inputs[i].span)
452 } else {
453 None
454 };
455 return Some(MethodViolationCode::ReferencesSelfInput(span));
456 }
457 }
458 if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
459 return Some(MethodViolationCode::ReferencesSelfOutput);
460 }
461 if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
462 return Some(code);
463 }
464
465 // We can't monomorphize things like `fn foo<A>(...)`.
466 let own_counts = tcx.generics_of(method.def_id).own_counts();
467 if own_counts.types + own_counts.consts != 0 {
468 return Some(MethodViolationCode::Generic);
469 }
470
471 let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
472
473 // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
474 // However, this is already considered object-safe. We allow it as a special case here.
475 // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
476 // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
477 if receiver_ty != tcx.types.self_param {
478 if !receiver_is_dispatchable(tcx, method, receiver_ty) {
479 let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
480 kind: hir::TraitItemKind::Fn(sig, _),
481 ..
482 })) = tcx.hir().get_if_local(method.def_id).as_ref()
483 {
484 Some(sig.decl.inputs[0].span)
485 } else {
486 None
487 };
488 return Some(MethodViolationCode::UndispatchableReceiver(span));
489 } else {
490 // Do sanity check to make sure the receiver actually has the layout of a pointer.
491
492 use rustc_target::abi::Abi;
493
494 let param_env = tcx.param_env(method.def_id);
495
496 let abi_of_ty = |ty: Ty<'tcx>| -> Option<Abi> {
497 match tcx.layout_of(param_env.and(ty)) {
498 Ok(layout) => Some(layout.abi),
499 Err(err) => {
500 // #78372
501 tcx.sess.delay_span_bug(
502 tcx.def_span(method.def_id),
503 format!("error: {err}\n while computing layout for type {ty:?}"),
504 );
505 None
506 }
507 }
508 };
509
510 // e.g., `Rc<()>`
511 let unit_receiver_ty =
512 receiver_for_self_ty(tcx, receiver_ty, Ty::new_unit(tcx), method.def_id);
513
514 match abi_of_ty(unit_receiver_ty) {
515 Some(Abi::Scalar(..)) => (),
516 abi => {
517 tcx.sess.delay_span_bug(
518 tcx.def_span(method.def_id),
519 format!(
520 "receiver when `Self = ()` should have a Scalar ABI; found {:?}",
521 abi
522 ),
523 );
524 }
525 }
526
527 let trait_object_ty = object_ty_for_trait(tcx, trait_def_id, tcx.lifetimes.re_static);
528
529 // e.g., `Rc<dyn Trait>`
530 let trait_object_receiver =
531 receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id);
532
533 match abi_of_ty(trait_object_receiver) {
534 Some(Abi::ScalarPair(..)) => (),
535 abi => {
536 tcx.sess.delay_span_bug(
537 tcx.def_span(method.def_id),
538 format!(
539 "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}",
540 trait_object_ty, abi
541 ),
542 );
543 }
544 }
545 }
546 }
547
548 // NOTE: This check happens last, because it results in a lint, and not a
549 // hard error.
550 if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| {
551 // dyn Trait is okay:
552 //
553 // trait Trait {
554 // fn f(&self) where Self: 'static;
555 // }
556 //
557 // because a trait object can't claim to live longer than the concrete
558 // type. If the lifetime bound holds on dyn Trait then it's guaranteed
559 // to hold as well on the concrete type.
560 if pred.as_type_outlives_clause().is_some() {
561 return false;
562 }
563
564 // dyn Trait is okay:
565 //
566 // auto trait AutoTrait {}
567 //
568 // trait Trait {
569 // fn f(&self) where Self: AutoTrait;
570 // }
571 //
572 // because `impl AutoTrait for dyn Trait` is disallowed by coherence.
573 // Traits with a default impl are implemented for a trait object if and
574 // only if the autotrait is one of the trait object's trait bounds, like
575 // in `dyn Trait + AutoTrait`. This guarantees that trait objects only
576 // implement auto traits if the underlying type does as well.
577 if let ty::ClauseKind::Trait(ty::TraitPredicate {
578 trait_ref: pred_trait_ref,
579 constness: ty::BoundConstness::NotConst,
580 polarity: ty::ImplPolarity::Positive,
581 }) = pred.kind().skip_binder()
582 && pred_trait_ref.self_ty() == tcx.types.self_param
583 && tcx.trait_is_auto(pred_trait_ref.def_id)
584 {
585 // Consider bounds like `Self: Bound<Self>`. Auto traits are not
586 // allowed to have generic parameters so `auto trait Bound<T> {}`
587 // would already have reported an error at the definition of the
588 // auto trait.
589 if pred_trait_ref.substs.len() != 1 {
590 tcx.sess.diagnostic().delay_span_bug(
591 span,
592 "auto traits cannot have generic parameters",
593 );
594 }
595 return false;
596 }
597
598 contains_illegal_self_type_reference(tcx, trait_def_id, pred)
599 }) {
600 return Some(MethodViolationCode::WhereClauseReferencesSelf);
601 }
602
603 None
604 }
605
606 /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
607 /// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
receiver_for_self_ty<'tcx>( tcx: TyCtxt<'tcx>, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, method_def_id: DefId, ) -> Ty<'tcx>608 fn receiver_for_self_ty<'tcx>(
609 tcx: TyCtxt<'tcx>,
610 receiver_ty: Ty<'tcx>,
611 self_ty: Ty<'tcx>,
612 method_def_id: DefId,
613 ) -> Ty<'tcx> {
614 debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
615 let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| {
616 if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
617 });
618
619 let result = EarlyBinder::bind(receiver_ty).subst(tcx, substs);
620 debug!(
621 "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
622 receiver_ty, self_ty, method_def_id, result
623 );
624 result
625 }
626
627 /// Creates the object type for the current trait. For example,
628 /// if the current trait is `Deref`, then this will be
629 /// `dyn Deref<Target = Self::Target> + 'static`.
630 #[instrument(level = "trace", skip(tcx), ret)]
object_ty_for_trait<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, lifetime: ty::Region<'tcx>, ) -> Ty<'tcx>631 fn object_ty_for_trait<'tcx>(
632 tcx: TyCtxt<'tcx>,
633 trait_def_id: DefId,
634 lifetime: ty::Region<'tcx>,
635 ) -> Ty<'tcx> {
636 let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
637 debug!(?trait_ref);
638
639 let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
640 ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
641 ));
642 debug!(?trait_predicate);
643
644 let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
645 let mut elaborated_predicates: Vec<_> = elaborate(tcx, [pred])
646 .filter_map(|pred| {
647 debug!(?pred);
648 let pred = pred.to_opt_poly_projection_pred()?;
649 Some(pred.map_bound(|p| {
650 ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
651 tcx, p,
652 ))
653 }))
654 })
655 .collect();
656 // NOTE: Since #37965, the existential predicates list has depended on the
657 // list of predicates to be sorted. This is mostly to enforce that the primary
658 // predicate comes first.
659 elaborated_predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
660 elaborated_predicates.dedup();
661
662 let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(
663 iter::once(trait_predicate).chain(elaborated_predicates),
664 );
665 debug!(?existential_predicates);
666
667 Ty::new_dynamic(tcx, existential_predicates, lifetime, ty::Dyn)
668 }
669
670 /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
671 /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
672 /// in the following way:
673 /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
674 /// - require the following bound:
675 ///
676 /// ```ignore (not-rust)
677 /// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
678 /// ```
679 ///
680 /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
681 /// (substitution notation).
682 ///
683 /// Some examples of receiver types and their required obligation:
684 /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
685 /// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
686 /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
687 ///
688 /// The only case where the receiver is not dispatchable, but is still a valid receiver
689 /// type (just not object-safe), is when there is more than one level of pointer indirection.
690 /// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
691 /// is no way, or at least no inexpensive way, to coerce the receiver from the version where
692 /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
693 /// contained by the trait object, because the object that needs to be coerced is behind
694 /// a pointer.
695 ///
696 /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
697 /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
698 /// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>).
699 /// Instead, we fudge a little by introducing a new type parameter `U` such that
700 /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
701 /// Written as a chalk-style query:
702 /// ```ignore (not-rust)
703 /// forall (U: Trait + ?Sized) {
704 /// if (Self: Unsize<U>) {
705 /// Receiver: DispatchFromDyn<Receiver[Self => U]>
706 /// }
707 /// }
708 /// ```
709 /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
710 /// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
711 /// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
712 //
713 // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
714 // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
715 // `self: Wrapper<Self>`.
716 #[allow(dead_code)]
receiver_is_dispatchable<'tcx>( tcx: TyCtxt<'tcx>, method: ty::AssocItem, receiver_ty: Ty<'tcx>, ) -> bool717 fn receiver_is_dispatchable<'tcx>(
718 tcx: TyCtxt<'tcx>,
719 method: ty::AssocItem,
720 receiver_ty: Ty<'tcx>,
721 ) -> bool {
722 debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
723
724 let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
725 let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else {
726 debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
727 return false;
728 };
729
730 // the type `U` in the query
731 // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now.
732 // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
733 // replace this with `dyn Trait`
734 let unsized_self_ty: Ty<'tcx> =
735 Ty::new_param(tcx, u32::MAX, Symbol::intern("RustaceansAreAwesome"));
736
737 // `Receiver[Self => U]`
738 let unsized_receiver_ty =
739 receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
740
741 // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
742 // `U: ?Sized` is already implied here
743 let param_env = {
744 let param_env = tcx.param_env(method.def_id);
745
746 // Self: Unsize<U>
747 let unsize_predicate =
748 ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty])
749 .to_predicate(tcx);
750
751 // U: Trait<Arg1, ..., ArgN>
752 let trait_predicate = {
753 let trait_def_id = method.trait_container(tcx).unwrap();
754 let substs = InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
755 if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
756 });
757
758 ty::TraitRef::new(tcx, trait_def_id, substs).to_predicate(tcx)
759 };
760
761 let caller_bounds =
762 param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]);
763
764 ty::ParamEnv::new(
765 tcx.mk_clauses_from_iter(caller_bounds),
766 param_env.reveal(),
767 param_env.constness(),
768 )
769 };
770
771 // Receiver: DispatchFromDyn<Receiver[Self => U]>
772 let obligation = {
773 let predicate =
774 ty::TraitRef::new(tcx, dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]);
775
776 Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
777 };
778
779 let infcx = tcx.infer_ctxt().build();
780 // the receiver is dispatchable iff the obligation holds
781 infcx.predicate_must_hold_modulo_regions(&obligation)
782 }
783
contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, value: T, ) -> bool784 fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
785 tcx: TyCtxt<'tcx>,
786 trait_def_id: DefId,
787 value: T,
788 ) -> bool {
789 // This is somewhat subtle. In general, we want to forbid
790 // references to `Self` in the argument and return types,
791 // since the value of `Self` is erased. However, there is one
792 // exception: it is ok to reference `Self` in order to access
793 // an associated type of the current trait, since we retain
794 // the value of those associated types in the object type
795 // itself.
796 //
797 // ```rust
798 // trait SuperTrait {
799 // type X;
800 // }
801 //
802 // trait Trait : SuperTrait {
803 // type Y;
804 // fn foo(&self, x: Self) // bad
805 // fn foo(&self) -> Self // bad
806 // fn foo(&self) -> Option<Self> // bad
807 // fn foo(&self) -> Self::Y // OK, desugars to next example
808 // fn foo(&self) -> <Self as Trait>::Y // OK
809 // fn foo(&self) -> Self::X // OK, desugars to next example
810 // fn foo(&self) -> <Self as SuperTrait>::X // OK
811 // }
812 // ```
813 //
814 // However, it is not as simple as allowing `Self` in a projected
815 // type, because there are illegal ways to use `Self` as well:
816 //
817 // ```rust
818 // trait Trait : SuperTrait {
819 // ...
820 // fn foo(&self) -> <Self as SomeOtherTrait>::X;
821 // }
822 // ```
823 //
824 // Here we will not have the type of `X` recorded in the
825 // object type, and we cannot resolve `Self as SomeOtherTrait`
826 // without knowing what `Self` is.
827
828 struct IllegalSelfTypeVisitor<'tcx> {
829 tcx: TyCtxt<'tcx>,
830 trait_def_id: DefId,
831 supertraits: Option<Vec<DefId>>,
832 }
833
834 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
835 type BreakTy = ();
836
837 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
838 match t.kind() {
839 ty::Param(_) => {
840 if t == self.tcx.types.self_param {
841 ControlFlow::Break(())
842 } else {
843 ControlFlow::Continue(())
844 }
845 }
846 ty::Alias(ty::Projection, ref data)
847 if self.tcx.is_impl_trait_in_trait(data.def_id) =>
848 {
849 // We'll deny these later in their own pass
850 ControlFlow::Continue(())
851 }
852 ty::Alias(ty::Projection, ref data) => {
853 // This is a projected type `<Foo as SomeTrait>::X`.
854
855 // Compute supertraits of current trait lazily.
856 if self.supertraits.is_none() {
857 let trait_ref =
858 ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
859 self.supertraits = Some(
860 traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
861 );
862 }
863
864 // Determine whether the trait reference `Foo as
865 // SomeTrait` is in fact a supertrait of the
866 // current trait. In that case, this type is
867 // legal, because the type `X` will be specified
868 // in the object type. Note that we can just use
869 // direct equality here because all of these types
870 // are part of the formal parameter listing, and
871 // hence there should be no inference variables.
872 let is_supertrait_of_current_trait = self
873 .supertraits
874 .as_ref()
875 .unwrap()
876 .contains(&data.trait_ref(self.tcx).def_id);
877
878 if is_supertrait_of_current_trait {
879 ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200
880 } else {
881 t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
882 }
883 }
884 _ => t.super_visit_with(self), // walk contained types, if any
885 }
886 }
887
888 fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
889 // Constants can only influence object safety if they are generic and reference `Self`.
890 // This is only possible for unevaluated constants, so we walk these here.
891 self.tcx.expand_abstract_consts(ct).super_visit_with(self)
892 }
893 }
894
895 value
896 .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
897 .is_break()
898 }
899
contains_illegal_impl_trait_in_trait<'tcx>( tcx: TyCtxt<'tcx>, fn_def_id: DefId, ty: ty::Binder<'tcx, Ty<'tcx>>, ) -> Option<MethodViolationCode>900 pub fn contains_illegal_impl_trait_in_trait<'tcx>(
901 tcx: TyCtxt<'tcx>,
902 fn_def_id: DefId,
903 ty: ty::Binder<'tcx, Ty<'tcx>>,
904 ) -> Option<MethodViolationCode> {
905 // This would be caught below, but rendering the error as a separate
906 // `async-specific` message is better.
907 if tcx.asyncness(fn_def_id).is_async() {
908 return Some(MethodViolationCode::AsyncFn);
909 }
910
911 // FIXME(RPITIT): Perhaps we should use a visitor here?
912 ty.skip_binder().walk().find_map(|arg| {
913 if let ty::GenericArgKind::Type(ty) = arg.unpack()
914 && let ty::Alias(ty::Projection, proj) = ty.kind()
915 && tcx.is_impl_trait_in_trait(proj.def_id)
916 {
917 Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
918 } else {
919 None
920 }
921 })
922 }
923
provide(providers: &mut Providers)924 pub fn provide(providers: &mut Providers) {
925 *providers = Providers {
926 object_safety_violations,
927 check_is_object_safe,
928 generics_require_sized_self,
929 ..*providers
930 };
931 }
932