diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index d00621d8254c3..5e284c52e11db 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -197,6 +197,8 @@ declare_features! ( (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR (internal, custom_mir, "1.65.0", None), + /// Allows using bunch of default auto traits + (unstable, default_auto_traits, "CURRENT_RUSTC_VERSION", None), /// Outputs useful `assert!` messages (unstable, generic_assert, "1.63.0", None), /// Allows using the `rust-intrinsic`'s "ABI". diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 8e327c029dffc..2736b3217b886 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -47,6 +47,13 @@ impl LanguageItems { .enumerate() .filter_map(|(i, id)| id.map(|id| (LangItem::from_u32(i as u32).unwrap(), id))) } + + pub fn is_default_trait(&self, def_id: DefId) -> bool { + DEFAULT_TRAITS + .iter() + .find(|&&default_trait| self.get(default_trait) == Some(def_id)) + .is_some() + } } // The actual lang items defined come at the end of this file in one handy table. @@ -139,6 +146,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { language_item_table! { // Variant name, Name, Getter method name, Target Generic requirements; + SyncDrop, sym::sync_drop, sync_drop_trait, Target::Trait, GenericRequirement::None; + Leak, sym::leak, leak_trait, Target::Trait, GenericRequirement::None; Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). @@ -349,6 +358,9 @@ pub enum GenericRequirement { Exact(usize), } +pub static DEFAULT_TRAITS: &'static [LangItem] = + &[LangItem::Sized, LangItem::Leak, LangItem::SyncDrop]; + pub static FN_TRAITS: &'static [LangItem] = &[LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]; pub static OPERATORS: &'static [LangItem] = &[ diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index 0cc50c6dd8505..16da56370574f 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -24,6 +24,8 @@ macro_rules! weak_lang_items { } weak_lang_items! { + SyncDrop, sync_drop; + Leak, leak; PanicImpl, rust_begin_unwind; EhPersonality, rust_eh_personality; EhCatchTypeinfo, rust_eh_catch_typeinfo; diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index e37119e7d4dc8..849d79003fada 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -16,19 +16,60 @@ use crate::bounds::Bounds; use crate::errors; impl<'tcx> dyn AstConv<'tcx> + '_ { - /// Sets `implicitly_sized` to true on `Bounds` if necessary - pub(crate) fn add_implicitly_sized( + /// Sets Sized or default_auto_traits to true on `Bounds` if necessary + pub(crate) fn add_implicit_traits( &self, bounds: &mut Bounds<'tcx>, self_ty: Ty<'tcx>, ast_bounds: &'tcx [hir::GenericBound<'tcx>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, span: Span, + ) { + hir::lang_items::DEFAULT_TRAITS.iter().for_each(|default_trait| { + self.add_implicit_trait( + *default_trait, + bounds, + self_ty, + ast_bounds, + self_ty_where_predicates, + span, + ); + }); + } + + pub(crate) fn add_implicit_trait( + &self, + trait_: hir::LangItem, + bounds: &mut Bounds<'tcx>, + self_ty: Ty<'tcx>, + ast_bounds: &'tcx [hir::GenericBound<'tcx>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + span: Span, ) { let tcx = self.tcx(); - let sized_def_id = tcx.lang_items().sized_trait(); - let mut seen_negative_sized_bound = false; - let mut seen_positive_sized_bound = false; + let trait_id = tcx.lang_items().get(trait_); + + if self.check_for_implicit_trait(trait_id, ast_bounds, self_ty_where_predicates) + && (trait_ == hir::LangItem::Sized || tcx.features().default_auto_traits) + { + // There was no `?Trait` or `!Trait` bound; + // add `Trait` if it's available. + bounds.push_lang_item_trait(tcx, self_ty, trait_, span); + } + } + + fn check_for_implicit_trait( + &self, + trait_def_id: Option, + ast_bounds: &'tcx [hir::GenericBound<'tcx>], + self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + ) -> bool { + let Some(trait_def_id) = trait_def_id else { + return false; + }; + let tcx = self.tcx(); + let mut seen_negative_bound = false; + let mut seen_positive_bound = false; // Try to find an unbound in bounds. let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); @@ -40,17 +81,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { match modifier { hir::TraitBoundModifier::Maybe => unbounds.push(ptr), hir::TraitBoundModifier::Negative => { - if let Some(sized_def_id) = sized_def_id - && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_negative_sized_bound = true; + if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { + seen_negative_bound = true; } } hir::TraitBoundModifier::None => { - if let Some(sized_def_id) = sized_def_id - && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_positive_sized_bound = true; + if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) { + seen_positive_bound = true; } } _ => {} @@ -68,36 +105,29 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } } - if unbounds.len() > 1 { - tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds { - spans: unbounds.iter().map(|ptr| ptr.span).collect(), - }); - } - - let mut seen_sized_unbound = false; + let mut seen_unbound = false; for unbound in unbounds { - if let Some(sized_def_id) = sized_def_id - && unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) - { - seen_sized_unbound = true; - continue; + let unbound_def_id = unbound.trait_ref.trait_def_id(); + if unbound_def_id == Some(trait_def_id) { + seen_unbound = true; } - // There was a `?Trait` bound, but it was not `?Sized`; warn. - tcx.dcx().span_warn( - unbound.span, - "relaxing a default bound only does something for `?Sized`; \ - all other traits are not bound by default", - ); - } - if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound { - // There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound; - // we don't need to do anything. - } else if sized_def_id.is_some() { - // There was no `?Sized`, `!Sized` or explicit `Sized` bound; - // add `Sized` if it's available. - bounds.push_sized(tcx, self_ty, span); + let emit_relax_err = || { + tcx.dcx().span_warn( + unbound.span, + "relaxing a default bound only does something for `?Sized` and `default_auto_traits`; \ + all other traits are not bound by default", + ); + }; + + match unbound_def_id { + Some(def_id) if !tcx.lang_items().is_default_trait(def_id) => emit_relax_err(), + None => emit_relax_err(), + _ => {} + } } + + !(seen_unbound || seen_negative_bound || seen_positive_bound) } /// This helper takes a *converted* parameter type (`param_ty`) diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 2d85ad5789ecc..6d0b1633f4e17 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -53,6 +53,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { potential_assoc_types.extend(cur_potential_assoc_types); } } + // FIXME: support polarity for trait objects + if tcx.features().default_auto_traits { + hir::lang_items::DEFAULT_TRAITS.iter().for_each(|default_trait| { + if *default_trait != hir::LangItem::Sized { + bounds.push_lang_item_trait(tcx, dummy_self, *default_trait, span); + } + }); + } let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index b69f679880dbf..f65ef8bf06bff 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -76,11 +76,24 @@ impl<'tcx> Bounds<'tcx> { )); } - pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { - let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); - let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); - // Preferable to put this obligation first, since we report better errors for sized ambiguity. - self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); + pub fn push_lang_item_trait( + &mut self, + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + lang_item: LangItem, + span: Span, + ) { + assert_eq!(lang_item.target(), rustc_hir::Target::Trait); + let Some(trait_def_id) = tcx.lang_items().get(lang_item) else { + return; + }; + let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]); + if lang_item == LangItem::Sized { + // Preferable to put this obligation first, since we report better errors for sized ambiguity. + self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); + } else { + self.clauses.push((trait_ref.to_predicate(tcx), span)); + } } pub fn clauses(&self) -> impl Iterator, Span)> + '_ { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b74431983113a..3d04369a6b5e1 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -316,8 +316,8 @@ fn bounds_from_generic_predicates<'tcx>( ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); - if Some(def_id) != tcx.lang_items().sized_trait() { - // Type params are `Sized` by default, do not add that restriction to the list + if !tcx.lang_items().is_default_trait(def_id) { + // Do not add that restriction to the list // if it is a positive requirement. entry.push(trait_predicate.def_id()); } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 39ca1bba06545..4e5d5787c7d3b 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -29,7 +29,7 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); // Associated types are implicitly sized unless a `?Sized` bound is found - icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); + icx.astconv().add_implicit_traits(&mut bounds, item_ty, ast_bounds, None, span); let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); @@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); // Opaque types are implicitly sized unless a `?Sized` bound is found - icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span); + icx.astconv().add_implicit_traits(&mut bounds, item_ty, ast_bounds, None, span); debug!(?bounds); tcx.arena.alloc_from_iter(bounds.clauses()) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index ab9ed6ef98d9f..c05da98f63c16 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -146,7 +146,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ItemKind::Trait(_, _, generics, self_bounds, ..) | ItemKind::TraitAlias(generics, self_bounds) => { - is_trait = Some(self_bounds); + is_trait = Some((self_bounds, item.span)); generics } ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics, @@ -169,11 +169,27 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // on a trait we must also consider the bounds that follow the trait's name, // like `trait Foo: A + B + C`. if let Some(self_bounds) = is_trait { - predicates.extend( - icx.astconv() - .compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All) - .clauses(), - ); + let mut bounds = + icx.astconv().compute_bounds(tcx.types.self_param, self_bounds.0, PredicateFilter::All); + + let sized_trait = tcx.lang_items().sized_trait(); + let trait_def_id = def_id.to_def_id(); + hir::lang_items::DEFAULT_TRAITS.iter().for_each(|default_trait| { + if *default_trait != hir::LangItem::Sized + && (Some(trait_def_id) == sized_trait + || !tcx.lang_items().is_default_trait(def_id.to_def_id())) + { + icx.astconv().add_implicit_trait( + *default_trait, + &mut bounds, + tcx.types.self_param, + self_bounds.0, + None, + self_bounds.1, + ); + } + }); + predicates.extend(bounds.clauses()); } // In default impls, we can assume that the self type implements @@ -199,7 +215,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let param_ty = icx.astconv().hir_id_to_bound_ty(param.hir_id); let mut bounds = Bounds::default(); // Params are implicitly sized unless a `?Sized` bound is found - icx.astconv().add_implicitly_sized( + icx.astconv().add_implicit_traits( &mut bounds, param_ty, &[], diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index bac5068a69b86..9bd81564003ca 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -894,25 +894,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); - let mut has_sized_bound = false; - let mut has_negative_sized_bound = false; + let mut default_trait_bounds = FxHashSet::default(); + let mut default_negative_trait_bounds = FxHashSet::default(); let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); - for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { + 'pred: for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); - // Don't print `+ Sized`, but rather `+ ?Sized` if absent. - if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { - match pred.polarity { - ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => { - has_sized_bound = true; - continue; + // Don't print implicit bounds. + for default_trait in hir::lang_items::DEFAULT_TRAITS { + let lang_item_id = tcx.lang_items().get(*default_trait); + if let Some(default_trait_id) = lang_item_id + && trait_ref.def_id() == default_trait_id + { + match pred.polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => { + default_trait_bounds.insert(*default_trait); + continue 'pred; + } + ty::ImplPolarity::Negative => { + default_negative_trait_bounds.insert(*default_trait); + } } - ty::ImplPolarity::Negative => has_negative_sized_bound = true, } } @@ -950,7 +957,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut first = true; // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait - let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; + let paren_needed = + fn_traits.len() > 1 || traits.len() > 0 || default_trait_bounds.is_empty(); for (fn_once_trait_ref, entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; @@ -1096,16 +1104,29 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { })?; } - let add_sized = has_sized_bound && (first || has_negative_sized_bound); - let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound; - if add_sized || add_maybe_sized { - if !first { - write!(self, " + ")?; - } - if add_maybe_sized { - write!(self, "?")?; + for default_trait in hir::lang_items::DEFAULT_TRAITS { + if *default_trait != LangItem::Sized && !tcx.features().default_auto_traits { + continue; + }; + + let has_default_bound = default_trait_bounds.contains(default_trait); + let has_negative_default_bound = default_negative_trait_bounds.contains(default_trait); + + let add_bound = has_default_bound && (first || has_negative_default_bound); + let add_maybe_bound = !has_default_bound && !has_negative_default_bound; + + if add_bound || add_maybe_bound { + if !first { + write!(self, " + ")?; + } else { + first = false; + } + + if add_maybe_bound { + write!(self, "?")?; + } + write!(self, "{}", default_trait.variant_name())?; } - write!(self, "Sized")?; } if !with_forced_trimmed_paths() { @@ -1286,6 +1307,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { auto_traits.sort_by_cached_key(|did| with_no_trimmed_paths!(self.tcx().def_path_str(*did))); for def_id in auto_traits { + if self.tcx().lang_items().is_default_trait(def_id) + && self.tcx().lang_items().sized_trait() != Some(def_id) + { + continue; + } if !first { p!(" + "); } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 3d0eb117d174f..bc76621103e49 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -1,5 +1,7 @@ //! Analysis of patterns, notably match exhaustiveness checking. +#![recursion_limit = "256"] + pub mod constructor; #[cfg(feature = "rustc")] pub mod errors; diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index ddd5ea5510a98..d030950202bfd 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -14,6 +14,7 @@ #![feature(rustdoc_internals)] #![allow(internal_features)] #![allow(rustc::usage_of_ty_tykind)] +#![recursion_limit = "256"] pub mod rustc_internal; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dbfc89c2d496e..28a5622c6fde2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -643,6 +643,7 @@ symbols! { declare_lint_pass, decode, default_alloc_error_handler, + default_auto_traits, default_fn, default_lib_allocator, default_method_body_is_const, @@ -932,6 +933,7 @@ symbols! { lazy_normalization_consts, lazy_type_alias, le, + leak, len, let_chains, let_else, @@ -1621,6 +1623,7 @@ symbols! { suggestion, sym, sync, + sync_drop, t32, target, target_abi, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index b185e4e5f8eb0..8c7a64f436762 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -906,6 +906,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)) } + // backward compatibility for default traits + ty::Foreign(..) if self.tcx().lang_items().is_default_trait(goal.predicate.def_id()) && self.tcx().lang_items().sized_trait() != Some(goal.predicate.def_id()) => { + Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) + }, + // These types cannot be structurally decomposed into constituent // types, and therefore have no built-in auto impl. ty::Dynamic(..) 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 a8715b0764f0a..bde302515fd13 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 @@ -157,7 +157,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // with more relevant type information and hide redundant E0282 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() => + if self.tcx.lang_items().is_default_trait(pred.def_id()) => { 1 } @@ -2379,7 +2379,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if self.tcx.lang_items().is_default_trait(trait_ref.def_id()) { match self.tainted_by_errors() { None => { let err = self.emit_inference_failure_err( diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 3289dfe343e1a..bc4e47c9d10a1 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -760,9 +760,22 @@ fn receiver_is_dispatchable<'tcx>( ty::TraitRef::new(tcx, trait_def_id, args).to_predicate(tcx) }; + let mut default_clauses = Vec::new(); + for default_trait in hir::lang_items::DEFAULT_TRAITS { + if let Some(default_trait_id) = tcx.lang_items().get(*default_trait) + && *default_trait != hir::LangItem::Sized + { + let default_clause: ty::Clause<'_> = + ty::TraitRef::new(tcx, default_trait_id, [unsized_self_ty]).to_predicate(tcx); + default_clauses.push(default_clause); + } + } - let caller_bounds = - param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]); + let caller_bounds = param_env + .caller_bounds() + .iter() + .chain([unsize_predicate, trait_predicate]) + .chain(default_clauses); ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds), param_env.reveal()) }; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 12aea88e9b6a2..25e60fbf77205 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -544,6 +544,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // we don't add any `..` impl. Default traits could // still be provided by a manual implementation for // this trait and type. + + // default traits are added due to backward compatibility. + if self.tcx().lang_items().is_default_trait(def_id) + && self.tcx().lang_items().sized_trait() != Some(def_id) + { + candidates.vec.push(AutoImplCandidate) + } } ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6a6adcbb680ea..a3124fded461d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2274,6 +2274,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never + | ty::Foreign(..) | ty::Char => ty::Binder::dummy(Vec::new()), // Treat this like `struct str([u8]);` @@ -2282,7 +2283,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Placeholder(..) | ty::Dynamic(..) | ty::Param(..) - | ty::Foreign(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index de08e7d2f0384..1a0619c145ccb 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -515,9 +515,13 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti for (p, _) in predicates { if let Some(poly_trait_ref) = p.as_trait_clause() { - if Some(poly_trait_ref.def_id()) == sized_trait { + let poly_trait_id = poly_trait_ref.def_id(); + if Some(poly_trait_id) == sized_trait { types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder()); continue; + } else if tcx.lang_items().is_default_trait(poly_trait_id) { + // Do not emit other default traits. They are for experiments only. + continue; } } pretty_predicates.push(p.to_string()); diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index c80389a3a4d52..ea81301bffb13 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -3,6 +3,7 @@ #![allow(dead_code, unused_variables)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![recursion_limit = "256"] #[macro_use] extern crate tracing; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index d6e0e1895cdff..1fec07491fe0e 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1095,3 +1095,19 @@ pub trait FnPtr: Copy + Clone { #[lang = "fn_ptr_addr"] fn addr(self) -> *const (); } + +/// A marker for linear types. +/// +/// todo: give a clear definition of linear types. +#[fundamental] +#[rustc_unsafe_specialization_marker] +#[unstable(feature = "default_auto_traits", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "leak")] +pub unsafe auto trait Leak {} + +/// todo +#[fundamental] +#[rustc_unsafe_specialization_marker] +#[unstable(feature = "default_auto_traits", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "sync_drop")] +pub unsafe auto trait SyncDrop {} diff --git a/tests/ui/feature-gates/feature-gate-default-auto-traits.rs b/tests/ui/feature-gates/feature-gate-default-auto-traits.rs new file mode 100644 index 0000000000000..19ce9fbefbea4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-default-auto-traits.rs @@ -0,0 +1,14 @@ +#![feature(negative_impls)] +use std::marker::{Leak, SyncDrop}; +//~^ ERROR use of unstable library feature 'default_auto_traits' +//~| ERROR use of unstable library feature 'default_auto_traits' + +struct S; + +impl !Leak for S {} +//~^ ERROR use of unstable library feature 'default_auto_traits' + +impl !SyncDrop for S {} +//~^ ERROR use of unstable library feature 'default_auto_traits' + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-default-auto-traits.stderr b/tests/ui/feature-gates/feature-gate-default-auto-traits.stderr new file mode 100644 index 0000000000000..362be57a9ada4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-default-auto-traits.stderr @@ -0,0 +1,39 @@ +error[E0658]: use of unstable library feature 'default_auto_traits' + --> $DIR/feature-gate-default-auto-traits.rs:2:19 + | +LL | use std::marker::{Leak, SyncDrop}; + | ^^^^ + | + = help: add `#![feature(default_auto_traits)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'default_auto_traits' + --> $DIR/feature-gate-default-auto-traits.rs:2:25 + | +LL | use std::marker::{Leak, SyncDrop}; + | ^^^^^^^^ + | + = help: add `#![feature(default_auto_traits)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'default_auto_traits' + --> $DIR/feature-gate-default-auto-traits.rs:8:7 + | +LL | impl !Leak for S {} + | ^^^^ + | + = help: add `#![feature(default_auto_traits)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'default_auto_traits' + --> $DIR/feature-gate-default-auto-traits.rs:11:7 + | +LL | impl !SyncDrop for S {} + | ^^^^^^^^ + | + = help: add `#![feature(default_auto_traits)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/issues/issue-37534.rs index 40f7186db098e..494525b150666 100644 --- a/tests/ui/issues/issue-37534.rs +++ b/tests/ui/issues/issue-37534.rs @@ -1,6 +1,8 @@ struct Foo {} //~^ ERROR expected trait, found derive macro `Hash` -//~^^ ERROR parameter `T` is never used -//~^^^ WARN relaxing a default bound only does something for `?Sized` +//~| ERROR parameter `T` is never used +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` fn main() {} diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index a687e733d3dae..ab4bf914e1638 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -9,12 +9,28 @@ help: consider importing this trait instead LL + use std::hash::Hash; | -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default --> $DIR/issue-37534.rs:1:15 | LL | struct Foo {} | ^^^^^ +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-37534.rs:1:15 + | +LL | struct Foo {} + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-37534.rs:1:15 + | +LL | struct Foo {} + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error[E0392]: type parameter `T` is never used --> $DIR/issue-37534.rs:1:12 | @@ -23,7 +39,7 @@ LL | struct Foo {} | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 3 warnings emitted Some errors have detailed explanations: E0392, E0404. For more information about an error, try `rustc --explain E0392`. diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs index d16d406767300..051bb42270263 100644 --- a/tests/ui/issues/issue-87199.rs +++ b/tests/ui/issues/issue-87199.rs @@ -6,11 +6,17 @@ // Check that these function definitions only emit warnings, not errors fn arg(_: T) {} -//~^ warning: relaxing a default bound only does something for `?Sized` +//~^ warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` fn ref_arg(_: &T) {} -//~^ warning: relaxing a default bound only does something for `?Sized` +//~^ warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` fn ret() -> impl Iterator + ?Send { std::iter::empty() } -//~^ warning: relaxing a default bound only does something for `?Sized` +//~^ warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits` // Check that there's no `?Sized` relaxation! fn main() { diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr index 34433eef5c70b..61d132023e1c0 100644 --- a/tests/ui/issues/issue-87199.stderr +++ b/tests/ui/issues/issue-87199.stderr @@ -1,30 +1,78 @@ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default --> $DIR/issue-87199.rs:8:11 | LL | fn arg(_: T) {} | ^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/issue-87199.rs:10:15 +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:8:11 + | +LL | fn arg(_: T) {} + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:8:11 + | +LL | fn arg(_: T) {} + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:12:15 + | +LL | fn ref_arg(_: &T) {} + | ^^^^^ + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:12:15 | LL | fn ref_arg(_: &T) {} | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:12:15 + | +LL | fn ref_arg(_: &T) {} + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:16:40 + | +LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } + | ^^^^^ + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:16:40 + | +LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/issue-87199.rs:12:40 +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/issue-87199.rs:16:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the size for values of type `[i32]` cannot be known at compilation time - --> $DIR/issue-87199.rs:18:15 + --> $DIR/issue-87199.rs:24:15 | LL | ref_arg::<[i32]>(&[5]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[i32]` note: required by an implicit `Sized` bound in `ref_arg` - --> $DIR/issue-87199.rs:10:12 + --> $DIR/issue-87199.rs:12:12 | LL | fn ref_arg(_: &T) {} | ^ required by the implicit `Sized` requirement on this type parameter in `ref_arg` @@ -33,6 +81,6 @@ help: consider relaxing the implicit `Sized` restriction LL | fn ref_arg(_: &T) {} | ++++++++ -error: aborting due to 1 previous error; 3 warnings emitted +error: aborting due to 1 previous error; 9 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default_auto_traits/lang_items.rs b/tests/ui/traits/default_auto_traits/lang_items.rs new file mode 100644 index 0000000000000..c060cdd98357d --- /dev/null +++ b/tests/ui/traits/default_auto_traits/lang_items.rs @@ -0,0 +1,16 @@ +// check-pass + +#![no_core] +#![feature( + default_auto_traits, + no_core, + lang_items, +)] + +#[lang = "sized"] +trait Sized {} + +// do not generate bounds for undeclared default auto traits +fn foo() {} + +fn main() {} diff --git a/tests/ui/traits/default_auto_traits/leak_basic.rs b/tests/ui/traits/default_auto_traits/leak_basic.rs new file mode 100644 index 0000000000000..8b8b7785b5fb5 --- /dev/null +++ b/tests/ui/traits/default_auto_traits/leak_basic.rs @@ -0,0 +1,15 @@ +#![feature(default_auto_traits)] +#![feature(negative_impls)] + +use std::marker::Leak; + +struct NeedDrop; + +impl !Leak for NeedDrop {} + +fn forget(_: T) {} + +fn main() { + forget(NeedDrop); + //~^ ERROR the trait bound `NeedDrop: Leak` is not satisfied +} diff --git a/tests/ui/traits/default_auto_traits/leak_basic.stderr b/tests/ui/traits/default_auto_traits/leak_basic.stderr new file mode 100644 index 0000000000000..6b63238c4796f --- /dev/null +++ b/tests/ui/traits/default_auto_traits/leak_basic.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `NeedDrop: Leak` is not satisfied + --> $DIR/leak_basic.rs:13:12 + | +LL | forget(NeedDrop); + | ------ ^^^^^^^^ the trait `Leak` is not implemented for `NeedDrop` + | | + | required by a bound introduced by this call + | +note: required by a bound in `forget` + --> $DIR/leak_basic.rs:10:14 + | +LL | fn forget(_: T) {} + | ^^^^ required by this bound in `forget` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unsized/maybe-bounds-where.rs b/tests/ui/unsized/maybe-bounds-where.rs index 7e82a3eb449cb..ff478212bb2c8 100644 --- a/tests/ui/unsized/maybe-bounds-where.rs +++ b/tests/ui/unsized/maybe-bounds-where.rs @@ -11,11 +11,14 @@ trait Trait<'a> {} struct S4(T) where for<'a> T: ?Trait<'a>; //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared -//~| WARN relaxing a default bound only does something for `?Sized` +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` struct S5(*const T) where T: ?Trait<'static> + ?Sized; -//~^ ERROR type parameter has more than one relaxed default bound -//~| WARN relaxing a default bound only does something for `?Sized` +//~^ WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` +//~| WARN relaxing a default bound only does something for `?Sized` and `default_auto_traits` impl S1 { fn f() where T: ?Sized {} diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/maybe-bounds-where.stderr index 683bd387bb292..32032bf54e0da 100644 --- a/tests/ui/unsized/maybe-bounds-where.stderr +++ b/tests/ui/unsized/maybe-bounds-where.stderr @@ -23,29 +23,54 @@ LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:21:21 + --> $DIR/maybe-bounds-where.rs:24:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default --> $DIR/maybe-bounds-where.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/maybe-bounds-where.rs:16:33 +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/maybe-bounds-where.rs:12:34 + | +LL | struct S4(T) where for<'a> T: ?Trait<'a>; + | ^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/maybe-bounds-where.rs:12:34 + | +LL | struct S4(T) where for<'a> T: ?Trait<'a>; + | ^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/maybe-bounds-where.rs:18:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; - | ^^^^^^^^^^^^^^^ ^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-bounds-where.rs:16:33 +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/maybe-bounds-where.rs:18:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: relaxing a default bound only does something for `?Sized` and `default_auto_traits`; all other traits are not bound by default + --> $DIR/maybe-bounds-where.rs:18:33 + | +LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; + | ^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 5 previous errors; 6 warnings emitted -For more information about this error, try `rustc --explain E0203`.