diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index dd44fdd889328..488a505531da2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -589,11 +589,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, mutate_fulfillment_errors: impl Fn(&mut Vec>), ) { - let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self); - if !result.is_empty() { - mutate_fulfillment_errors(&mut result); - self.adjust_fulfillment_errors_for_expr_obligation(&mut result); - self.err_ctxt().report_fulfillment_errors(result); + let mut errors = self.fulfillment_cx.borrow_mut().select_where_possible(self); + if !errors.is_empty() { + mutate_fulfillment_errors(&mut errors); + if errors.is_empty() { + // We sometimes skip reporting fulfillment errors while constructing + // a different error. + self.dcx().span_delayed_bug( + self.tcx.def_span(self.body_id), + "skipped reporting fulfillment errors", + ); + return; + } + self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); + self.err_ctxt().report_fulfillment_errors(errors); } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index d24bec5a766b9..d0d0e904380ed 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -541,22 +541,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { .instantiate(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) } - ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { - // This is the "fallback impl" for type parameters, unnormalizable projections - // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. - // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't - // exist. Instead, `Pointee` should be a supertrait of `Sized`. - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - DUMMY_SP, - [ty::GenericArg::from(goal.predicate.self_ty())], - ); - // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? - ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate)); - tcx.types.unit - } - ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { None => tcx.types.unit, Some(tail_def) => { @@ -571,6 +555,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]), }, + // The metadata of these types can only be known from param env or alias bound + // candidates. + ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => return Err(NoSolution), + ty::Infer( ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), ) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 4bc3ff92a6751..4f4675e97bdd8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -80,61 +80,81 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( #[extension(pub trait TypeErrCtxtExt<'tcx>)] impl<'tcx> TypeErrCtxt<'_, 'tcx> { + #[instrument(skip(self), level = "debug")] fn report_fulfillment_errors( &self, mut errors: Vec>, ) -> ErrorGuaranteed { + if errors.is_empty() { + bug!("attempted to report fulfillment errors, but there we no errors"); + } + self.sub_relations .borrow_mut() .add_constraints(self, errors.iter().map(|e| e.obligation.predicate)); + let mut reported = None; + + // We want to ignore desugarings when filtering errors: spans are equivalent even + // if one is the result of a desugaring and the other is not. + let strip_desugaring = |span: Span| { + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { expn_data.call_site } else { span } + }; + #[derive(Debug)] - struct ErrorDescriptor<'tcx> { + struct ErrorDescriptor<'tcx, 'err> { predicate: ty::Predicate<'tcx>, - index: Option, // None if this is an old error + source: Option<(usize, &'err FulfillmentError<'tcx>)>, // None if this is an old error } let mut error_map: FxIndexMap<_, Vec<_>> = self .reported_trait_errors .borrow() .iter() - .map(|(&span, predicates)| { - ( - span, - predicates - .0 - .iter() - .map(|&predicate| ErrorDescriptor { predicate, index: None }) - .collect(), - ) + .map(|(&span, &(ref predicates, guar))| { + reported = Some(guar); + let span = strip_desugaring(span); + let reported_errors = predicates + .iter() + .map(|&predicate| ErrorDescriptor { predicate, source: None }) + .collect(); + (span, reported_errors) }) .collect(); + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + enum ErrorOrd { + Default, + Sized, + Metadata, + Coerce, + WellFormed, + } + // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics - // with more relevant type information and hide redundant E0282 errors. + // with more relevant type information and hide redundant E0282 ("type annotations needed") errors. errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() => { - 1 + ErrorOrd::Sized + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) + if Some(pred.def_id()) == self.tcx.lang_items().metadata_type() => + { + ErrorOrd::Metadata } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, - ty::PredicateKind::Coerce(_) => 2, - _ => 0, + ty::PredicateKind::Coerce(_) => ErrorOrd::Coerce, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => ErrorOrd::WellFormed, + _ => ErrorOrd::Default, }); for (index, error) in errors.iter().enumerate() { - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - + let span = strip_desugaring(error.obligation.cause.span); error_map.entry(span).or_default().push(ErrorDescriptor { predicate: error.obligation.predicate, - index: Some(index), + source: Some((index, error)), }); } @@ -144,59 +164,63 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { for (_, error_set) in error_map.iter() { // We want to suppress "duplicate" errors with the same span. for error in error_set { - if let Some(index) = error.index { + let Some((index, error_source)) = error.source else { + continue; + }; + + for error2 in error_set { // Suppress errors that are either: // 1) strictly implied by another error. // 2) implied by an error with a smaller index. - for error2 in error_set { - if error2.index.is_some_and(|index2| is_suppressed[index2]) { - // Avoid errors being suppressed by already-suppressed - // errors, to prevent all errors from being suppressed - // at once. - continue; - } + if self.error_implied_by(error.predicate, error2.predicate) + && (!error2.source.is_some_and(|(index2, _)| index2 >= index) + || !self.error_implied_by(error2.predicate, error.predicate)) + { + info!("skipping `{}` (implied by `{}`)", error.predicate, error2.predicate); + is_suppressed[index] = true; + break; + } - if self.error_implies(error2.predicate, error.predicate) - && !(error2.index >= error.index - && self.error_implies(error.predicate, error2.predicate)) - { - info!("skipping {:?} (implied by {:?})", error, error2); - is_suppressed[index] = true; - break; - } + // Also suppress the error if we are absolutely certain that a different + // error is the one that the user should fix. This will suppress errors + // about `::Metadata == ()` that can be fixed by `T: Sized`. + if error.predicate.to_opt_poly_projection_pred().is_some() + && error2.predicate.to_opt_poly_trait_pred().is_some() + && self.error_fixed_by( + error_source.obligation.clone(), + error2.predicate.expect_clause(), + ) + { + info!("skipping `{}` (fixed by `{}`)", error.predicate, error2.predicate); + is_suppressed[index] = true; + break; } } } } - let mut reported = None; - for from_expansion in [false, true] { - for (error, suppressed) in iter::zip(&errors, &is_suppressed) { - if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { - let guar = self.report_fulfillment_error(error); - reported = Some(guar); - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - self.reported_trait_errors - .borrow_mut() - .entry(span) - .or_insert_with(|| (vec![], guar)) - .0 - .push(error.obligation.predicate); + for (error, &suppressed) in iter::zip(&errors, &is_suppressed) { + let span = error.obligation.cause.span; + if suppressed || span.from_expansion() != from_expansion { + continue; } + + let guar = self.report_fulfillment_error(error); + reported = Some(guar); + + self.reported_trait_errors + .borrow_mut() + .entry(span) + .or_insert_with(|| (vec![], guar)) + .0 + .push(error.obligation.predicate); } } - // It could be that we don't report an error because we have seen an `ErrorReported` from - // another source. We should probably be able to fix most of these, but some are delayed - // bugs that get a proper error after this function. - reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) + // If all errors are suppressed, then we must have reported at least one error + // from a previous call to this function. + reported.unwrap_or_else(|| bug!("failed to report fulfillment errors")) } /// Reports that an overflow has occurred and halts compilation. We @@ -1465,10 +1489,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && self.can_eq(param_env, goal.term, assumption.term) } - // returns if `cond` not occurring implies that `error` does not occur - i.e., that - // `error` occurring implies that `cond` occurs. + /// Returns whether `cond` not occurring implies that `error` does not occur - i.e., that + /// `error` occurring implies that `cond` occurs. #[instrument(level = "debug", skip(self), ret)] - fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { + fn error_implied_by(&self, error: ty::Predicate<'tcx>, cond: ty::Predicate<'tcx>) -> bool { if cond == error { return true; } @@ -1490,6 +1514,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } + /// Returns whether fixing `cond` will also fix `error`. + #[instrument(level = "debug", skip(self), ret)] + fn error_fixed_by(&self, mut error: PredicateObligation<'tcx>, cond: ty::Clause<'tcx>) -> bool { + self.probe(|_| { + let ocx = ObligationCtxt::new(self); + + let clauses = elaborate(self.tcx, std::iter::once(cond)).collect::>(); + let clauses = ocx.normalize(&error.cause, error.param_env, clauses); + let mut clauses = self.resolve_vars_if_possible(clauses); + + if clauses.has_infer() { + return false; + } + + clauses.extend(error.param_env.caller_bounds()); + let clauses = self.tcx.mk_clauses(&clauses); + error.param_env = ty::ParamEnv::new(clauses, error.param_env.reveal()); + + ocx.register_obligation(error); + ocx.select_all_or_error().is_empty() + }) + } + #[instrument(skip(self), level = "debug")] fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default() diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6756b5dec2318..ab5855ebc325a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -23,7 +23,6 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{BoundRegionConversionTime, InferOk}; use crate::traits::normalize::normalize_with_depth; use crate::traits::normalize::normalize_with_depth_to; -use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::select::ProjectionMatchesProjection; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -975,9 +974,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // // NOTE: This should be kept in sync with the similar code in // `rustc_ty_utils::instance::resolve_associated_item()`. - let node_item = - specialization_graph::assoc_def(selcx.tcx(), impl_data.impl_def_id, obligation.predicate.def_id) - .map_err(|ErrorGuaranteed { .. }| ())?; + let node_item = specialization_graph::assoc_def( + selcx.tcx(), + impl_data.impl_def_id, + obligation.predicate.def_id, + ) + .map_err(|ErrorGuaranteed { .. }| ())?; if node_item.is_final() { // Non-specializable items are always projectable. @@ -1020,7 +1022,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( lang_items.async_fn_trait(), lang_items.async_fn_mut_trait(), lang_items.async_fn_once_trait(), - ].contains(&Some(trait_ref.def_id)) + ] + .contains(&Some(trait_ref.def_id)) { true } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) { @@ -1033,7 +1036,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( true } else { obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() - && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() + && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() } } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { match self_ty.kind() { @@ -1072,24 +1075,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Error(_) => false, } } else if lang_items.pointee_trait() == Some(trait_ref.def_id) { - let tail = selcx.tcx().struct_tail_with_normalize( - self_ty, - |ty| { - // We throw away any obligations we get from this, since we normalize - // and confirm these obligations once again during confirmation - normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty, - ) - .value - }, - || {}, - ); - - match tail.kind() { + match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -1110,40 +1096,30 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Never // Extern types have unit metadata, according to RFC 2850 | ty::Foreign(_) - // If returned by `struct_tail_without_normalization` this is a unit struct - // without any fields, or not a struct, and therefore is Sized. + // The metadata of an ADT or tuple is the metadata of its tail, + // or unit if it has no tail. | ty::Adt(..) - // If returned by `struct_tail_without_normalization` this is the empty tuple. | ty::Tuple(..) - // Integers and floats are always Sized, and so have unit type metadata. - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + // Integers and floats are always sized, and so have unit type metadata. + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) + // The metadata of `{type error}` is `{type error}`. + | ty::Error(_) => true, - // We normalize from `Wrapper::Metadata` to `Tail::Metadata` if able. - // Otherwise, type parameters, opaques, and unnormalized projections have - // unit metadata if they're known (e.g. by the param_env) to be sized. - ty::Param(_) | ty::Alias(..) - if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions( - &obligation.with( - selcx.tcx(), - ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]), - ), - ) => - { - true - } + // The metadata of these types can only be known from param env candidates. + ty::Param(_) | ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) => false, - // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? - ty::Param(_) - | ty::Alias(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) - | ty::Error(_) => { - if tail.has_infer_types() { - candidate_set.mark_ambiguous(); - } + ty::Infer(ty::TyVar(_)) => { + candidate_set.mark_ambiguous(); false } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + span_bug!( + obligation.cause.span, + "unexpected self ty `{self_ty:?}` when normalizing \ + `::Metadata`", + ) + } } } else { bug!("unexpected builtin trait with associated type: {trait_ref:?}") @@ -1190,7 +1166,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation.cause.span, format!("Cannot project an associated type from `{impl_source:?}`"), ); - return Err(()) + return Err(()); } }; @@ -1488,47 +1464,79 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let lang_items = tcx.lang_items(); let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); - let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + let mut potentially_unnormalized = false; + let term = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); assert_eq!(discriminant_def_id, item_def_id); - (self_ty.discriminant_ty(tcx).into(), Vec::new()) + self_ty.discriminant_ty(tcx).into() } else if lang_items.pointee_trait() == Some(trait_def_id) { let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, item_def_id); - let mut obligations = Vec::new(); - let normalize = |ty| { - normalize_with_depth_to( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty, - &mut obligations, - ) - }; - let metadata_ty = self_ty.ptr_metadata_ty_or_tail(tcx, normalize).unwrap_or_else(|tail| { - if tail == self_ty { - // This is the "fallback impl" for type parameters, unnormalizable projections - // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. - // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't - // exist. Instead, `Pointee` should be a supertrait of `Sized`. - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - obligation.cause.span(), - [self_ty], + let metadata_ty = match self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Array(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Foreign(..) + | ty::Dynamic(_, _, ty::DynStar) => tcx.types.unit, + + ty::Error(e) => Ty::new_error(tcx, *e), + + ty::Str | ty::Slice(_) => tcx.types.usize, + + ty::Dynamic(_, _, ty::Dyn) => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + tcx.type_of(dyn_metadata).instantiate(tcx, &[self_ty.into()]) + } + + ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { + None => tcx.types.unit, + Some(tail_def) => { + // We know that `self_ty` has the same metadata as its tail. This allows us + // to prove predicates like `Wrapper::Metadata == Tail::Metadata`. + let tail_ty = tail_def.ty(tcx, args); + potentially_unnormalized = true; + Ty::new_projection(tcx, metadata_def_id, [tail_ty]) + } + }, + ty::Adt(_, _) => tcx.types.unit, + + ty::Tuple(elements) => match elements.last() { + None => tcx.types.unit, + Some(&tail_ty) => { + potentially_unnormalized = true; + Ty::new_projection(tcx, metadata_def_id, [tail_ty]) + } + }, + + ty::Param(_) + | ty::Alias(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + span_bug!( + obligation.cause.span, + "`<{self_ty:?} as Pointee>::Metadata` projection candidate assembled, \ + but we cannot project further", ); - obligations.push(obligation.with(tcx, sized_predicate)); - tcx.types.unit - } else { - // We know that `self_ty` has the same metadata as `tail`. This allows us - // to prove predicates like `Wrapper::Metadata == Tail::Metadata`. - Ty::new_projection(tcx, metadata_def_id, [tail]) } - }); - (metadata_ty.into(), obligations) + }; + + metadata_ty.into() } else { bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate); }; @@ -1536,9 +1544,13 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let predicate = ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, item_def_id, args), term }; - confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) - .with_addl_obligations(obligations) - .with_addl_obligations(data) + confirm_param_env_candidate( + selcx, + obligation, + ty::Binder::dummy(predicate), + potentially_unnormalized, + ) + .with_addl_obligations(data) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a56a2578c2241..5fd0e0195bf1a 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -142,6 +142,19 @@ unsafe impl Send for &T {} #[rustc_specialization_trait] #[rustc_deny_explicit_impl(implement_via_object = false)] #[rustc_coinductive] +#[cfg(not(bootstrap))] +pub trait Sized: crate::ptr::Thin { + // Empty. +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[lang = "sized"] +#[fundamental] +#[rustc_specialization_trait] +#[rustc_deny_explicit_impl(implement_via_object = false)] +#[rustc_coinductive] +#[cfg(bootstrap)] +#[allow(missing_docs)] pub trait Sized { // Empty. } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index c234e4f9b110c..d8d078d1a3a42 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{ }; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{Obligation, ObligationCause}; +use rustc_trait_selection::traits::{self, Obligation, ObligationCause}; use super::UNNECESSARY_TO_OWNED; @@ -323,9 +323,10 @@ fn check_other_call_arg<'tcx>( && let (input, n_refs) = peel_mid_ty_refs(*input) && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input) && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait() + && let sized_super_def_ids = traits::supertrait_def_ids(cx.tcx, sized_def_id).collect::>() && let [trait_predicate] = trait_predicates .iter() - .filter(|trait_predicate| trait_predicate.def_id() != sized_def_id) + .filter(|trait_predicate| !sized_super_def_ids.contains(&trait_predicate.def_id())) .collect::>()[..] && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index a32bca3d03816..d50b172e21b40 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{Obligation, ObligationCause}; +use rustc_trait_selection::traits::{self, Obligation, ObligationCause}; use std::collections::VecDeque; declare_clippy_lint! { @@ -171,6 +171,10 @@ fn needless_borrow_count<'tcx>( let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); let drop_trait_def_id = cx.tcx.lang_items().drop_trait(); + let sized_super_def_ids = sized_trait_def_id.map_or_else(Vec::new, |sized_def_id| { + traits::supertrait_def_ids(cx.tcx, sized_def_id).collect() + }); + let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder(); let predicates = cx.tcx.param_env(fn_id).caller_bounds(); let projection_predicates = predicates @@ -203,7 +207,7 @@ fn needless_borrow_count<'tcx>( }) .all(|trait_def_id| { Some(trait_def_id) == destruct_trait_def_id - || Some(trait_def_id) == sized_trait_def_id + || sized_super_def_ids.contains(&trait_def_id) || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id) }) { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index f33e2e0ed71aa..0bad6ac52dc08 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -118,13 +118,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ]; let sized_trait = need!(cx.tcx.lang_items().sized_trait()); + let sized_super_traits = traits::supertrait_def_ids(cx.tcx, sized_trait).collect::>(); let preds = traits::elaborate(cx.tcx, cx.param_env.caller_bounds().iter()) .filter(|p| !p.is_global()) .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. match pred.kind().no_bound_vars() { - Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => Some(pred), + Some(ty::ClauseKind::Trait(pred)) if !sized_super_traits.contains(&pred.def_id()) => Some(pred), _ => None, } }) diff --git a/src/tools/miri/tests/fail/layout_cycle.rs b/src/tools/miri/tests/fail/layout_cycle.rs index 3e0dd881db84e..2ea96ef7649da 100644 --- a/src/tools/miri/tests/fail/layout_cycle.rs +++ b/src/tools/miri/tests/fail/layout_cycle.rs @@ -5,6 +5,7 @@ use std::mem; pub struct S { pub f: ::I, + _tail: (), // without this, we get an overflow error instead } pub trait Tr { diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index b31689dbf7365..00c91c3e4f072 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -32,6 +32,11 @@ LL | impl Node LL | where LL | P::Pointer>: Sized, | ^^^^^ unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `(dyn Deref> + 'static): Thin` + which is required by `(dyn Deref> + 'static): Sized` + `<(dyn Deref> + 'static) as Pointee>::Metadata = ()` + which is required by `(dyn Deref> + 'static): Sized` error: aborting due to 2 previous errors diff --git a/tests/ui/layout/layout-cycle.rs b/tests/ui/layout/layout-cycle.rs index 3c930def43b2b..406dbcd5a45cd 100644 --- a/tests/ui/layout/layout-cycle.rs +++ b/tests/ui/layout/layout-cycle.rs @@ -8,6 +8,7 @@ use std::mem; pub struct S { pub f: ::I, + _tail: (), // without this, we get an overflow error instead } pub trait Tr { diff --git a/tests/ui/sized/recursive-type-coercion-from-never.rs b/tests/ui/sized/recursive-type-coercion-from-never.rs index 7bd87ae06c5e4..5f5a501990968 100644 --- a/tests/ui/sized/recursive-type-coercion-from-never.rs +++ b/tests/ui/sized/recursive-type-coercion-from-never.rs @@ -9,8 +9,8 @@ impl A for () { type Assoc = Foo<()>; } -struct Foo(T::Assoc); +struct Foo(T::Assoc, ()); fn main() { - Foo::<()>(todo!()); + Foo::<()>(todo!(), ()); } diff --git a/tests/ui/sized/recursive-type-pass.rs b/tests/ui/sized/recursive-type-pass.rs index bffca39ffcbbf..1831b7363f82c 100644 --- a/tests/ui/sized/recursive-type-pass.rs +++ b/tests/ui/sized/recursive-type-pass.rs @@ -5,6 +5,6 @@ impl A for () { // FIXME: it would be nice for this to at least cause a warning. type Assoc = Foo<()>; } -struct Foo(T::Assoc); +struct Foo(T::Assoc, ()); fn main() {} diff --git a/tests/ui/sized/recursive-type-tail.rs b/tests/ui/sized/recursive-type-tail.rs new file mode 100644 index 0000000000000..6efa2f56f21e2 --- /dev/null +++ b/tests/ui/sized/recursive-type-tail.rs @@ -0,0 +1,11 @@ +//@ check-fail + +trait A { type Assoc; } + +impl A for () { + type Assoc = Foo<()>; + //~^ ERROR overflow evaluating the requirement ` as Pointee>::Metadata == ()` +} +struct Foo(T::Assoc); + +fn main() {} diff --git a/tests/ui/sized/recursive-type-tail.stderr b/tests/ui/sized/recursive-type-tail.stderr new file mode 100644 index 0000000000000..7ce0dec89afb7 --- /dev/null +++ b/tests/ui/sized/recursive-type-tail.stderr @@ -0,0 +1,21 @@ +error[E0275]: overflow evaluating the requirement ` as Pointee>::Metadata == ()` + --> $DIR/recursive-type-tail.rs:6:18 + | +LL | type Assoc = Foo<()>; + | ^^^^^^^ + | + = note: required for `<() as A>::Assoc` to implement `Thin` + = note: required for `<() as A>::Assoc` to implement `Sized` +note: required by a bound in `A::Assoc` + --> $DIR/recursive-type-tail.rs:3:11 + | +LL | trait A { type Assoc; } + | ^^^^^^^^^^^ required by this bound in `A::Assoc` +help: consider relaxing the implicit `Sized` restriction + | +LL | trait A { type Assoc: ?Sized; } + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.rs b/tests/ui/trait-bounds/super-assoc-mismatch.rs index 97dfec80e3167..c2fc484f1c97c 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.rs +++ b/tests/ui/trait-bounds/super-assoc-mismatch.rs @@ -6,6 +6,8 @@ impl Super for () { } trait Sub: Super {} +// direct impls (no nested obligations): + trait BoundOnSelf: Sub {} impl BoundOnSelf for () {} //~^ ERROR the trait bound `(): Sub` is not satisfied @@ -25,7 +27,7 @@ impl BoundOnAssoc for () { trait BoundOnGat where Self::Assoc: Sub { type Assoc; } -impl BoundOnGat for u8 { +impl BoundOnGat for () { type Assoc = (); //~^ ERROR the trait bound `(): Sub` is not satisfied } @@ -33,6 +35,33 @@ impl BoundOnGat for u8 { fn trivial_bound() where (): Sub {} //~^ ERROR the trait bound `(): Sub` is not satisfied +// blanket impls with nested obligations: + +struct Wrapper(T); +impl Super for Wrapper { + type Assoc = T::Assoc; +} +impl Sub for Wrapper {} + +impl BoundOnSelf for Wrapper<()> {} +//~^ ERROR the trait bound `(): Sub` is not satisfied + +impl BoundOnParam> for Wrapper<()> {} +//~^ ERROR the trait bound `(): Sub` is not satisfied + +impl BoundOnAssoc for Wrapper<()> { + type Assoc = Wrapper<()>; + //~^ ERROR the trait bound `(): Sub` is not satisfied +} + +impl BoundOnGat for Wrapper<()> { + type Assoc = Wrapper<()>; + //~^ ERROR the trait bound `(): Sub` is not satisfied +} + +fn trivial_bound_wrapper() where Wrapper<()>: Sub {} +//~^ ERROR the trait bound `(): Sub` is not satisfied + // The following is an edge case where the unsatisfied projection predicate // `<::Assoc1<()> as SuperGeneric>::Assoc == ::Assoc2` // contains both associated types of `MultiAssoc`. To suppress the error about the unsatisfied diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.stderr b/tests/ui/trait-bounds/super-assoc-mismatch.stderr index f2c5eb47e5981..0fdc9b7eb0dcb 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.stderr +++ b/tests/ui/trait-bounds/super-assoc-mismatch.stderr @@ -1,82 +1,162 @@ error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:10:22 + --> $DIR/super-assoc-mismatch.rs:12:22 | LL | impl BoundOnSelf for () {} | ^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 - | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnSelf` - --> $DIR/super-assoc-mismatch.rs:9:20 + --> $DIR/super-assoc-mismatch.rs:11:20 | LL | trait BoundOnSelf: Sub {} | ^^^ required by this bound in `BoundOnSelf` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:14:27 + --> $DIR/super-assoc-mismatch.rs:16:27 | LL | impl BoundOnParam<()> for () {} | ^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 - | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnParam` - --> $DIR/super-assoc-mismatch.rs:13:23 + --> $DIR/super-assoc-mismatch.rs:15:23 | LL | trait BoundOnParam {} | ^^^ required by this bound in `BoundOnParam` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:21:18 + --> $DIR/super-assoc-mismatch.rs:23:18 | LL | type Assoc = (); | ^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 - | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnAssoc::Assoc` - --> $DIR/super-assoc-mismatch.rs:18:17 + --> $DIR/super-assoc-mismatch.rs:20:17 | LL | type Assoc: Sub; | ^^^ required by this bound in `BoundOnAssoc::Assoc` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:29:21 + --> $DIR/super-assoc-mismatch.rs:31:21 | LL | type Assoc = (); - | ^^ the trait `Sub` is not implemented for `()`, which is required by `::Assoc: Sub` - | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 + | ^^ the trait `Sub` is not implemented for `()`, which is required by `<() as BoundOnGat>::Assoc: Sub` | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnGat` - --> $DIR/super-assoc-mismatch.rs:25:41 + --> $DIR/super-assoc-mismatch.rs:27:41 | LL | trait BoundOnGat where Self::Assoc: Sub { | ^^^ required by this bound in `BoundOnGat` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:33:26 + --> $DIR/super-assoc-mismatch.rs:35:26 | LL | fn trivial_bound() where (): Sub {} | ^^^^^^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 + = help: the trait `Sub` is implemented for `Wrapper` + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:46:22 + | +LL | impl BoundOnSelf for Wrapper<()> {} + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnSelf` + --> $DIR/super-assoc-mismatch.rs:11:20 + | +LL | trait BoundOnSelf: Sub {} + | ^^^ required by this bound in `BoundOnSelf` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:49:36 + | +LL | impl BoundOnParam> for Wrapper<()> {} + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnParam` + --> $DIR/super-assoc-mismatch.rs:15:23 + | +LL | trait BoundOnParam {} + | ^^^ required by this bound in `BoundOnParam` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:53:18 + | +LL | type Assoc = Wrapper<()>; + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnAssoc::Assoc` + --> $DIR/super-assoc-mismatch.rs:20:17 + | +LL | type Assoc: Sub; + | ^^^ required by this bound in `BoundOnAssoc::Assoc` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:58:21 + | +LL | type Assoc = Wrapper<()>; + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by ` as BoundOnGat>::Assoc: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnGat` + --> $DIR/super-assoc-mismatch.rs:27:41 + | +LL | trait BoundOnGat where Self::Assoc: Sub { + | ^^^ required by this bound in `BoundOnGat` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:62:34 + | +LL | fn trivial_bound_wrapper() where Wrapper<()>: Sub {} + | ^^^^^^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | @@ -84,18 +164,18 @@ LL + #![feature(trivial_bounds)] | error[E0277]: the trait bound `(): SubGeneric` is not satisfied - --> $DIR/super-assoc-mismatch.rs:55:22 + --> $DIR/super-assoc-mismatch.rs:84:22 | LL | type Assoc1 = (); | ^^ the trait `SubGeneric` is not implemented for `()`, which is required by `::Assoc1<()>: SubGeneric<::Assoc2>` | help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:43:1 + --> $DIR/super-assoc-mismatch.rs:72:1 | LL | trait SubGeneric: SuperGeneric {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `MultiAssoc` - --> $DIR/super-assoc-mismatch.rs:46:23 + --> $DIR/super-assoc-mismatch.rs:75:23 | LL | trait MultiAssoc | ---------- required by a bound in this trait @@ -103,6 +183,6 @@ LL | where LL | Self::Assoc1<()>: SubGeneric | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MultiAssoc` -error: aborting due to 6 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/bad-sized.stderr b/tests/ui/traits/bad-sized.stderr index 4c1835dfed085..0d05dfa872830 100644 --- a/tests/ui/traits/bad-sized.stderr +++ b/tests/ui/traits/bad-sized.stderr @@ -9,33 +9,33 @@ LL | let x: Vec = Vec::new(); = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:12 | LL | let x: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 | LL | let x: Vec = Vec::new(); | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` note: required by a bound in `Vec::::new` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 | LL | let x: Vec = Vec::new(); | ^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL diff --git a/tests/ui/traits/issue-32963.rs b/tests/ui/traits/issue-32963.rs index 56a68f3a2312c..9c0bb6833adb2 100644 --- a/tests/ui/traits/issue-32963.rs +++ b/tests/ui/traits/issue-32963.rs @@ -2,10 +2,10 @@ use std::mem; trait Misc {} -fn size_of_copy() -> usize { mem::size_of::() } +fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); //~^ ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied + //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied } diff --git a/tests/ui/traits/issue-32963.stderr b/tests/ui/traits/issue-32963.stderr index bad45e54d6428..057420c78748a 100644 --- a/tests/ui/traits/issue-32963.stderr +++ b/tests/ui/traits/issue-32963.stderr @@ -9,16 +9,16 @@ LL | size_of_copy::(); = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied +error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied --> $DIR/issue-32963.rs:8:20 | LL | size_of_copy::(); - | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` + | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` | note: required by a bound in `size_of_copy` --> $DIR/issue-32963.rs:5:20 | -LL | fn size_of_copy() -> usize { mem::size_of::() } +LL | fn size_of_copy() -> usize { mem::size_of::() } | ^^^^ required by this bound in `size_of_copy` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/pointee-normalize-equate.rs b/tests/ui/traits/pointee-normalize-equate.rs index 3edb010a827b8..5b7a1901c6731 100644 --- a/tests/ui/traits/pointee-normalize-equate.rs +++ b/tests/ui/traits/pointee-normalize-equate.rs @@ -26,6 +26,14 @@ fn wrapper_to_unit(ptr: *const ()) -> *const Wrapper { cast_same_meta(ptr) } +// normalize `Wrapper::Metadata` -> `()` +fn wrapper_to_unit2(ptr: *const ()) -> *const Wrapper +where + Wrapper: Sized, +{ + cast_same_meta(ptr) +} + trait Project { type Assoc: ?Sized; } @@ -45,8 +53,16 @@ where cast_same_meta(ptr) } -// normalize `<[T] as Pointee>::Metadata` -> `usize`, even if `[T]: Sized` -fn sized_slice(ptr: *const [T]) -> *const str +// normalize `WrapperProject::Metadata` -> `T::Assoc::Metadata` -> `()` +fn wrapper_project_unit2(ptr: *const ()) -> *const WrapperProject +where + WrapperProject: Sized, +{ + cast_same_meta(ptr) +} + +// if `[T]: Sized`, then normalize `<[T] as Pointee>::Metadata` -> `()` +fn sized_slice(ptr: *const ()) -> *const [T] where [T]: Sized, { diff --git a/tests/ui/traits/pointee-normalize-shallow.rs b/tests/ui/traits/pointee-normalize-shallow.rs new file mode 100644 index 0000000000000..032a0dc738efc --- /dev/null +++ b/tests/ui/traits/pointee-normalize-shallow.rs @@ -0,0 +1,20 @@ +//@ check-pass + +#![feature(ptr_metadata)] + +use std::ptr::Thin; + +struct Wrapper(T); + +fn check_thin() {} + +// Test that normalization of ` as Pointee>::Metadata` respects the +// `<[T] as Pointee>::Metadata == ()` bound from the param env. +fn foo() +where + [T]: Thin, +{ + check_thin::>(); +} + +fn main() {}