From 257b8e4199d29bc01eb93d013cb4d9d6e17caeeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 15:35:22 +0200 Subject: [PATCH 1/8] HIR ty lowering: Simplify signature of `lower_poly_trait_ref` --- .../src/hir_ty_lowering/bounds.rs | 6 +---- .../src/hir_ty_lowering/dyn_compatibility.rs | 24 ++++++----------- .../src/hir_ty_lowering/mod.rs | 13 ++++++---- .../const-trait-bounds-trait-objects.rs | 2 ++ .../const-trait-bounds-trait-objects.stderr | 26 +++++++++++++++++-- 5 files changed, 43 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index ea1dfdfd80619..5ec7f0d6438ac 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -480,12 +480,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match hir_bound { hir::GenericBound::Trait(poly_trait_ref) => { - let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers; let _ = self.lower_poly_trait_ref( - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - polarity, + poly_trait_ref, param_ty, bounds, predicate_filter, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 05465b47a26a8..0005c9702234c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -17,9 +17,7 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::errors::SelfInTypeAlias; -use crate::hir_ty_lowering::{ - GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason, -}; +use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a trait object type from the HIR to our internal notion of a type. @@ -37,24 +35,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut user_written_bounds = Vec::new(); let mut potential_assoc_types = Vec::new(); - for trait_bound in hir_bounds.iter() { - if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity { + for poly_trait_ref in hir_bounds.iter() { + if let hir::BoundPolarity::Maybe(_) = poly_trait_ref.modifiers.polarity { continue; } - if let GenericArgCountResult { - correct: - Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), - .. - } = self.lower_poly_trait_ref( - &trait_bound.trait_ref, - trait_bound.span, - hir::BoundConstness::Never, - hir::BoundPolarity::Positive, + let result = self.lower_poly_trait_ref( + poly_trait_ref, dummy_self, &mut user_written_bounds, PredicateFilter::SelfOnly, - ) { - potential_assoc_types.extend(cur_potential_assoc_types); + ); + if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct { + potential_assoc_types.extend(invalid_args); } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index b99f7b44661ec..b11d37fe1cf9a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -750,17 +750,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` /// where `'a` is a bound region at depth 0. Similarly, the `trait_ref` would be `Bar<'a>`. /// The lowered poly-trait-ref will track this binder explicitly, however. - #[instrument(level = "debug", skip(self, span, constness, bounds))] + #[instrument(level = "debug", skip(self, bounds))] pub(crate) fn lower_poly_trait_ref( &self, - trait_ref: &hir::TraitRef<'tcx>, - span: Span, - constness: hir::BoundConstness, - polarity: hir::BoundPolarity, + poly_trait_ref: &hir::PolyTraitRef<'tcx>, self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, ) -> GenericArgCountResult { + // We use the *resolved* bound vars later instead of the HIR ones since the former + // also include the bound vars of the overarching predicate if applicable. + let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } = + *poly_trait_ref; + let hir::TraitBoundModifiers { constness, polarity } = modifiers; + let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); let trait_segment = trait_ref.path.segments.last().unwrap(); diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs index 2dac1970835d2..f695b8df45642 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs @@ -14,5 +14,7 @@ fn main() { trait NonConst {} const fn handle(_: &dyn const NonConst) {} //~^ ERROR const trait bounds are not allowed in trait object types +//~| ERROR `const` can only be applied to `#[const_trait]` traits const fn take(_: &dyn ~const NonConst) {} //~^ ERROR `~const` is not allowed here +//~| ERROR `~const` can only be applied to `#[const_trait]` traits diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr index bd29b4b860b62..fb26e1c238e79 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr @@ -19,12 +19,34 @@ LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `~const` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:17:23 + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 | LL | const fn take(_: &dyn ~const NonConst) {} | ^^^^^^ | = note: trait objects cannot have `~const` trait bounds -error: aborting due to 4 previous errors +error: `const` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:15:25 + | +LL | const fn handle(_: &dyn const NonConst) {} + | ^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 + | +LL | const fn take(_: &dyn ~const NonConst) {} + | ^^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: aborting due to 6 previous errors From 95ca416912aff73ed6576041746f0eefb43d030d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 16:43:38 +0200 Subject: [PATCH 2/8] HIR ty lowering: Validate relaxed bounds in trait object types Only relevant to the internal feature `more_maybe_bounds`. --- .../src/hir_ty_lowering/dyn_compatibility.rs | 3 --- .../maybe-bounds-in-dyn-traits.rs | 4 +++ .../maybe-bounds-in-dyn-traits.stderr | 25 +++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 0005c9702234c..821e0ea780def 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -36,9 +36,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut user_written_bounds = Vec::new(); let mut potential_assoc_types = Vec::new(); for poly_trait_ref in hir_bounds.iter() { - if let hir::BoundPolarity::Maybe(_) = poly_trait_ref.modifiers.polarity { - continue; - } let result = self.lower_poly_trait_ref( poly_trait_ref, dummy_self, diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs index 5069cd256b277..e7cca41a47eab 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs @@ -64,4 +64,8 @@ fn main() { x.leak_foo(); //~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied x.maybe_leak_foo(); + // Ensure that we validate the generic args of relaxed bounds in trait object types. + let _: dyn Trait + ?Leak<(), Undefined = ()>; + //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR associated type `Undefined` not found for `Leak` } diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr index 48745e40268d4..350233b7cbe9d 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr @@ -18,6 +18,27 @@ note: required by a bound in `Trait::leak_foo` LL | fn leak_foo(&self) {} | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo` -error: aborting due to 2 previous errors +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/maybe-bounds-in-dyn-traits.rs:68:25 + | +LL | let _: dyn Trait + ?Leak<(), Undefined = ()>; + | ^^^^-------------------- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/maybe-bounds-in-dyn-traits.rs:44:12 + | +LL | auto trait Leak {} + | ^^^^ + +error[E0220]: associated type `Undefined` not found for `Leak` + --> $DIR/maybe-bounds-in-dyn-traits.rs:68:34 + | +LL | let _: dyn Trait + ?Leak<(), Undefined = ()>; + | ^^^^^^^^^ associated type `Undefined` not found + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0107, E0220, E0277. +For more information about an error, try `rustc --explain E0107`. From e9a4f724d9511fee97c72a4f12f0384131ae008d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 17:02:51 +0200 Subject: [PATCH 3/8] Update comment about `where Ty:` We no longer move trait predicates where the self ty is a ty param to "the bounds of a ty param". --- .../src/collect/predicates_of.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index c337765c5fec3..e033eec5a8fbe 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -266,20 +266,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen match predicate.kind { hir::WherePredicateKind::BoundPredicate(bound_pred) => { let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty); - let bound_vars = tcx.late_bound_vars(predicate.hir_id); - // Keep the type around in a dummy predicate, in case of no bounds. - // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` - // is still checked for WF. + + // This is a `where Ty:` (sic!). if bound_pred.bounds.is_empty() { if let ty::Param(_) = ty.kind() { - // This is a `where T:`, which can be in the HIR from the - // transformation that moves `?Sized` to `T`'s declaration. - // We can skip the predicate because type parameters are - // trivially WF, but also we *should*, to avoid exposing - // users who never wrote `where Type:,` themselves, to - // compiler/tooling bugs from not handling WF predicates. + // We can skip the predicate because type parameters are trivially WF. } else { + // Keep the type around in a dummy predicate. That way, it's not a complete + // noop (see #53696) and `Ty` is still checked for WF. + let span = bound_pred.bounded_ty.span; let predicate = ty::Binder::bind_with_vars( ty::ClauseKind::WellFormed(ty.into()), From b43747d48b23e1af479a308d6e2fc38506abaf1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 18 Jun 2025 22:10:53 +0200 Subject: [PATCH 4/8] AST lowering: More robustly deal with relaxed bounds --- compiler/rustc_ast_lowering/messages.ftl | 3 - compiler/rustc_ast_lowering/src/errors.rs | 7 - compiler/rustc_ast_lowering/src/item.rs | 111 +++++---------- compiler/rustc_ast_lowering/src/lib.rs | 126 +++++++++++++++--- compiler/rustc_ast_passes/messages.ftl | 5 - .../rustc_ast_passes/src/ast_validation.rs | 23 ---- compiler/rustc_ast_passes/src/errors.rs | 16 --- ...issing-associated_item_or_field_def_ids.rs | 5 +- ...ng-associated_item_or_field_def_ids.stderr | 24 ++-- ...ing-associated-items-of-undefined-trait.rs | 5 +- ...associated-items-of-undefined-trait.stderr | 27 ++-- .../feature-gate-more-maybe-bounds.stderr | 17 ++- tests/ui/maybe-bounds.stderr | 2 +- .../sized-hierarchy/default-supertrait.stderr | 4 +- ...re.rs => relaxed-bounds-invalid-places.rs} | 3 + ...r => relaxed-bounds-invalid-places.stderr} | 16 +-- 16 files changed, 185 insertions(+), 209 deletions(-) rename tests/ui/unsized/{maybe-bounds-where.rs => relaxed-bounds-invalid-places.rs} (85%) rename tests/ui/unsized/{maybe-bounds-where.stderr => relaxed-bounds-invalid-places.stderr} (87%) diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index c6472fd45fa98..370b15d2871a9 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -127,9 +127,6 @@ ast_lowering_misplaced_impl_trait = `impl Trait` is not allowed in {$position} .note = `impl Trait` is only allowed in arguments and return types of functions and methods -ast_lowering_misplaced_relax_trait_bound = - `?Trait` bounds are only permitted at the point where a type parameter is declared - ast_lowering_never_pattern_with_body = a never pattern is always unreachable .label = this will never be executed diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index b444324ef9143..83f3a976e83f7 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -324,13 +324,6 @@ pub(crate) struct MisplacedDoubleDot { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_lowering_misplaced_relax_trait_bound)] -pub(crate) struct MisplacedRelaxTraitBound { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_lowering_match_arm_with_no_body)] pub(crate) struct MatchArmWithNoBody { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ef27d0ef69b14..4071ad42f81d3 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -15,14 +15,11 @@ use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; -use super::errors::{ - InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault, - UnionWithDefault, -}; +use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault}; use super::stability::{enabled_names, gate_unstable_abi}; use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, - ResolverAstLoweringExt, + RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt, }; pub(super) struct ItemLowerer<'a, 'hir> { @@ -427,6 +424,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let bounds = this.lower_param_bounds( bounds, + RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::SuperTrait), ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ); let items = this.arena.alloc_from_iter( @@ -447,6 +445,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { this.lower_param_bounds( bounds, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ) }, @@ -938,6 +937,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::TraitItemKind::Type( this.lower_param_bounds( bounds, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ), ty, @@ -1703,61 +1703,6 @@ impl<'hir> LoweringContext<'_, 'hir> { assert!(self.impl_trait_defs.is_empty()); assert!(self.impl_trait_bounds.is_empty()); - // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. - // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering - // these into hir when we lower thee where clauses), but this makes it quite difficult to - // keep track of the Span info. Now, `::add_implicit_sized_bound` - // checks both param bounds and where clauses for `?Sized`. - for pred in &generics.where_clause.predicates { - let WherePredicateKind::BoundPredicate(bound_pred) = &pred.kind else { - continue; - }; - let compute_is_param = || { - // Check if the where clause type is a plain type parameter. - match self - .resolver - .get_partial_res(bound_pred.bounded_ty.id) - .and_then(|r| r.full_res()) - { - Some(Res::Def(DefKind::TyParam, def_id)) - if bound_pred.bound_generic_params.is_empty() => - { - generics - .params - .iter() - .any(|p| def_id == self.local_def_id(p.id).to_def_id()) - } - // Either the `bounded_ty` is not a plain type parameter, or - // it's not found in the generic type parameters list. - _ => false, - } - }; - // We only need to compute this once per `WherePredicate`, but don't - // need to compute this at all unless there is a Maybe bound. - let mut is_param: Option = None; - for bound in &bound_pred.bounds { - if !matches!( - *bound, - GenericBound::Trait(PolyTraitRef { - modifiers: TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }, - .. - }) - ) { - continue; - } - let is_param = *is_param.get_or_insert_with(compute_is_param); - if !is_param && !self.tcx.features().more_maybe_bounds() { - self.tcx - .sess - .create_feature_err( - MisplacedRelaxTraitBound { span: bound.span() }, - sym::more_maybe_bounds, - ) - .emit(); - } - } - } - let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new(); predicates.extend(generics.params.iter().filter_map(|param| { self.lower_generic_bound_predicate( @@ -1767,6 +1712,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ¶m.bounds, param.colon_span, generics.span, + RelaxedBoundPolicy::Allowed, itctx, PredicateOrigin::GenericParam, ) @@ -1776,7 +1722,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .where_clause .predicates .iter() - .map(|predicate| self.lower_where_predicate(predicate)), + .map(|predicate| self.lower_where_predicate(predicate, &generics.params)), ); let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self @@ -1853,6 +1799,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds: &[GenericBound], colon_span: Option, parent_span: Span, + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, origin: PredicateOrigin, ) -> Option> { @@ -1861,7 +1808,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return None; } - let bounds = self.lower_param_bounds(bounds, itctx); + let bounds = self.lower_param_bounds(bounds, rbp, itctx); let param_span = ident.span; @@ -1913,7 +1860,11 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(hir::WherePredicate { hir_id, span, kind }) } - fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { + fn lower_where_predicate( + &mut self, + pred: &WherePredicate, + params: &[ast::GenericParam], + ) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); self.lower_attrs(hir_id, &pred.attrs, span); @@ -1922,17 +1873,28 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params, bounded_ty, bounds, - }) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: self - .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), - bounded_ty: self - .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - bounds: self.lower_param_bounds( - bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), - ), - origin: PredicateOrigin::WhereClause, - }), + }) => { + let rbp = match bound_generic_params.is_empty() { + true => RelaxedBoundPolicy::AllowedIfOnTyParam(bounded_ty.id, params), + false => RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::BoundVars), + }; + hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { + bound_generic_params: self.lower_generic_params( + bound_generic_params, + hir::GenericParamSource::Binder, + ), + bounded_ty: self.lower_ty( + bounded_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), + bounds: self.lower_param_bounds( + bounds, + rbp, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), + origin: PredicateOrigin::WhereClause, + }) + } WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime: self.lower_lifetime( @@ -1942,6 +1904,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), bounds: self.lower_param_bounds( bounds, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), in_where_clause: true, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 26d7c0cd6d38f..58a024437dcf9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -53,14 +53,14 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::lints::DelayedLint; use rustc_hir::{ - self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, - LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate, + self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource, + LifetimeSyntax, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; -use rustc_session::parse::add_feature_diagnostics; +use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use smallvec::SmallVec; @@ -276,6 +276,20 @@ impl ResolverAstLowering { } } +#[derive(Clone, Copy, Debug)] +enum RelaxedBoundPolicy<'a> { + Allowed, + AllowedIfOnTyParam(NodeId, &'a [ast::GenericParam]), + Forbidden(RelaxedBoundForbiddenReason), +} + +#[derive(Clone, Copy, Debug)] +enum RelaxedBoundForbiddenReason { + TraitObjectTy, + SuperTrait, + BoundVars, +} + /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, /// and if so, what meaning it has. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -1079,10 +1093,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar))); hir::AssocItemConstraintKind::Equality { term: err_ty.into() } } else { - // Desugar `AssocTy: Bounds` into an assoc type binding where the - // later desugars into a trait predicate. - let bounds = self.lower_param_bounds(bounds, itctx); - + // FIXME(#135229): These should be forbidden! + let bounds = + self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx); hir::AssocItemConstraintKind::Bound { bounds } } } @@ -1210,6 +1223,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, span: t.span, }, + RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::TraitObjectTy), itctx, ); let bounds = this.arena.alloc_from_iter([bound]); @@ -1265,7 +1279,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parenthesized: hir::GenericArgsParentheses::No, span_ext: span, }); - let path = self.make_lang_item_qpath(LangItem::Pin, span, Some(args)); + let path = self.make_lang_item_qpath(hir::LangItem::Pin, span, Some(args)); hir::TyKind::Path(path) } TyKind::BareFn(f) => { @@ -1326,7 +1340,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // takes care of rejecting invalid modifier combinations and // const trait bounds in trait object types. GenericBound::Trait(ty) => { - let trait_ref = this.lower_poly_trait_ref(ty, itctx); + let trait_ref = this.lower_poly_trait_ref( + ty, + RelaxedBoundPolicy::Forbidden( + RelaxedBoundForbiddenReason::TraitObjectTy, + ), + itctx, + ); Some(trait_ref) } GenericBound::Outlives(lifetime) => { @@ -1381,9 +1401,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } path } - ImplTraitContext::InBinding => { - hir::TyKind::TraitAscription(self.lower_param_bounds(bounds, itctx)) - } + ImplTraitContext::InBinding => hir::TyKind::TraitAscription( + self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx), + ), ImplTraitContext::FeatureGated(position, feature) => { let guar = self .tcx @@ -1499,7 +1519,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { - this.lower_param_bounds(bounds, itctx) + this.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx) }) } @@ -1793,10 +1813,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bound( &mut self, tpb: &GenericBound, + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> hir::GenericBound<'hir> { match tpb { - GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)), + GenericBound::Trait(p) => { + hir::GenericBound::Trait(self.lower_poly_trait_ref(p, rbp, itctx)) + } GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime( lifetime, LifetimeSource::OutlivesBound, @@ -2011,19 +2034,77 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn lower_poly_trait_ref( &mut self, - p: &PolyTraitRef, + tr: &PolyTraitRef, + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> hir::PolyTraitRef<'hir> { + let PolyTraitRef { ref bound_generic_params, modifiers, ref trait_ref, span } = *tr; + let bound_generic_params = - self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); - let trait_ref = self.lower_trait_ref(p.modifiers, &p.trait_ref, itctx); - let modifiers = self.lower_trait_bound_modifiers(p.modifiers); + self.lower_lifetime_binder(trait_ref.ref_id, bound_generic_params); + let trait_ref = self.lower_trait_ref(modifiers, trait_ref, itctx); + let modifiers = self.lower_trait_bound_modifiers(modifiers); + + if let ast::BoundPolarity::Maybe(_) = modifiers.polarity { + self.validate_relaxed_bound(trait_ref, span, rbp); + } + hir::PolyTraitRef { bound_generic_params, modifiers, trait_ref, - span: self.lower_span(p.span), + span: self.lower_span(span), + } + } + + fn validate_relaxed_bound( + &self, + trait_ref: hir::TraitRef<'_>, + span: Span, + rbp: RelaxedBoundPolicy<'_>, + ) { + let err = |message| feature_err(&self.tcx.sess, sym::more_maybe_bounds, span, message); + + match rbp { + RelaxedBoundPolicy::Allowed => return, + RelaxedBoundPolicy::AllowedIfOnTyParam(id, params) => { + if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res()) + && let Res::Def(DefKind::TyParam, def_id) = res + && params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id()) + { + return; + } + if self.tcx.features().more_maybe_bounds() { + return; + } + } + RelaxedBoundPolicy::Forbidden(reason) => { + if self.tcx.features().more_maybe_bounds() { + return; + } + + match reason { + RelaxedBoundForbiddenReason::TraitObjectTy => { + err("`?Trait` is not permitted in trait object types").emit(); + return; + } + RelaxedBoundForbiddenReason::SuperTrait => { + let mut diag = err("`?Trait` is not permitted in supertraits"); + if let Some(def_id) = trait_ref.trait_def_id() + && self.tcx.is_lang_item(def_id, hir::LangItem::Sized) + { + diag.note("traits are `?Sized` by default"); + } + diag.emit(); + return; + } + RelaxedBoundForbiddenReason::BoundVars => {} + }; + } } + + err("`?Trait` bounds are only permitted at the point where a type parameter is declared") + .emit(); } fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { @@ -2034,17 +2115,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bounds( &mut self, bounds: &[GenericBound], + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> hir::GenericBounds<'hir> { - self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) + self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, rbp, itctx)) } fn lower_param_bounds_mut( &mut self, bounds: &[GenericBound], + rbp: RelaxedBoundPolicy<'_>, itctx: ImplTraitContext, ) -> impl Iterator> { - bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) + bounds.iter().map(move |bound| self.lower_param_bound(bound, rbp, itctx)) } #[instrument(level = "debug", skip(self), ret)] @@ -2078,6 +2161,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, /* colon_span */ None, span, + RelaxedBoundPolicy::Allowed, ImplTraitContext::Universal, hir::PredicateOrigin::ImplTrait, ); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 9a267501230fe..d9e95490c0b44 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -207,11 +207,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax .help = use `auto trait Trait {"{}"}` instead -ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types - -ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits - .note = traits are `?{$path_str}` by default - ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters .suggestion = reorder the parameters: lifetimes, then consts and types diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b69a91e2f5f86..472dc12b7bfd9 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1320,29 +1320,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match bound { GenericBound::Trait(trait_ref) => { match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds() => - { - self.sess - .create_feature_err( - errors::OptionalTraitSupertrait { - span: trait_ref.span, - path_str: pprust::path_to_string(&trait_ref.trait_ref.path), - }, - sym::more_maybe_bounds, - ) - .emit(); - } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) - if !self.features.more_maybe_bounds() => - { - self.sess - .create_feature_err( - errors::OptionalTraitObject { span: trait_ref.span }, - sym::more_maybe_bounds, - ) - .emit(); - } ( BoundKind::TraitObject, BoundConstness::Always(_), diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c437e62f4d373..e0c7953c8adfe 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -565,22 +565,6 @@ pub(crate) struct NestedLifetimes { pub span: Span, } -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_supertrait)] -#[note] -pub(crate) struct OptionalTraitSupertrait { - #[primary_span] - pub span: Span, - pub path_str: String, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_optional_trait_object)] -pub(crate) struct OptionalTraitObject { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_const_bound_trait_object)] pub(crate) struct ConstBoundTraitObject { diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs index b90bb9ea4ddf6..18c71e5c74429 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs @@ -1,8 +1,7 @@ // Regression test for . fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { - //~^ ERROR `?Trait` is not permitted in trait object types - //~| ERROR expected trait, found associated function `Iterator::advance_by` - //~| ERROR the value of the associated type `Item` in `Iterator` must be specified + //~^ ERROR expected trait, found associated function `Iterator::advance_by` + //~| ERROR `?Trait` is not permitted in trait object types todo!() } diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr index 7f0fbc800ed1c..6ec8e01c78d38 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr @@ -1,25 +1,19 @@ -error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29 - | -LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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[E0404]: expected trait, found associated function `Iterator::advance_by` --> $DIR/missing-associated_item_or_field_def_ids.rs:3:30 | LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait -error[E0191]: the value of the associated type `Item` in `Iterator` must be specified - --> $DIR/missing-associated_item_or_field_def_ids.rs:3:18 +error[E0658]: `?Trait` is not permitted in trait object types + --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29 | LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { - | ^^^^^^^^ help: specify the associated type: `Iterator` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0191, E0404, E0658. -For more information about an error, try `rustc --explain E0191`. +Some errors have detailed explanations: E0404, E0658. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs index f6b749a5100b9..9e0a86abb2e0b 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs @@ -6,7 +6,6 @@ trait Tr { fn main() { let _: dyn Tr + ?Foo; - //~^ ERROR: `?Trait` is not permitted in trait object types - //~| ERROR: cannot find trait `Foo` in this scope - //~| ERROR: the value of the associated type `Item` in `Tr` must be specified + //~^ ERROR: cannot find trait `Foo` in this scope + //~| ERROR: `?Trait` is not permitted in trait object types } diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr index f31a1de76a790..bd83c1a9ea892 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr @@ -1,28 +1,19 @@ -error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21 - | -LL | let _: dyn Tr + ?Foo; - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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[E0405]: cannot find trait `Foo` in this scope --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:22 | LL | let _: dyn Tr + ?Foo; | ^^^ not found in this scope -error[E0191]: the value of the associated type `Item` in `Tr` must be specified - --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:16 +error[E0658]: `?Trait` is not permitted in trait object types + --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21 | -LL | type Item; - | --------- `Item` defined here -... LL | let _: dyn Tr + ?Foo; - | ^^ help: specify the associated type: `Tr` + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(more_maybe_bounds)]` 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 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0191, E0405, E0658. -For more information about an error, try `rustc --explain E0191`. +Some errors have detailed explanations: E0405, E0658. +For more information about an error, try `rustc --explain E0405`. diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index 729df4eb37cac..f52532a035b46 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -4,24 +4,23 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait Trait3: ?Trait1 {} | ^^^^^^^ | - = note: traits are `?Trait1` by default = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types - --> $DIR/feature-gate-more-maybe-bounds.rs:10:28 +error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared + --> $DIR/feature-gate-more-maybe-bounds.rs:7:26 | -LL | fn foo(_: Box) {} - | ^^^^^^^ +LL | trait Trait4 where Self: ?Trait1 {} + | ^^^^^^^ | = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/feature-gate-more-maybe-bounds.rs:7:26 +error[E0658]: `?Trait` is not permitted in trait object types + --> $DIR/feature-gate-more-maybe-bounds.rs:10:28 | -LL | trait Trait4 where Self: ?Trait1 {} - | ^^^^^^^ +LL | fn foo(_: Box) {} + | ^^^^^^^ | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/maybe-bounds.stderr b/tests/ui/maybe-bounds.stderr index 230d11fd0ae66..84a4329ff21d2 100644 --- a/tests/ui/maybe-bounds.stderr +++ b/tests/ui/maybe-bounds.stderr @@ -4,9 +4,9 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait Tr: ?Sized {} | ^^^^^^ | - = note: traits are `?Sized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: traits are `?Sized` by default error[E0658]: `?Trait` is not permitted in trait object types --> $DIR/maybe-bounds.rs:4:20 diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr index de23936b900bc..0cb4f346a6300 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.stderr +++ b/tests/ui/sized-hierarchy/default-supertrait.stderr @@ -4,9 +4,9 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait NegSized: ?Sized { } | ^^^^^^ | - = note: traits are `?Sized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: traits are `?Sized` by default error[E0658]: `?Trait` is not permitted in supertraits --> $DIR/default-supertrait.rs:13:21 @@ -14,7 +14,6 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait NegMetaSized: ?MetaSized { } | ^^^^^^^^^^ | - = note: traits are `?MetaSized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -24,7 +23,6 @@ error[E0658]: `?Trait` is not permitted in supertraits LL | trait NegPointeeSized: ?PointeeSized { } | ^^^^^^^^^^^^^ | - = note: traits are `?PointeeSized` by default = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/unsized/maybe-bounds-where.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs similarity index 85% rename from tests/ui/unsized/maybe-bounds-where.rs rename to tests/ui/unsized/relaxed-bounds-invalid-places.rs index 4c4141631a7c5..ce3f35608bebb 100644 --- a/tests/ui/unsized/maybe-bounds-where.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -1,3 +1,6 @@ +// Test that relaxed bounds can only be placed on type parameters defined by the closest item +// (ignoring relaxed bounds inside `impl Trait` and in associated type defs here). + struct S1(T) where (T): ?Sized; //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared diff --git a/tests/ui/unsized/maybe-bounds-where.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr similarity index 87% rename from tests/ui/unsized/maybe-bounds-where.stderr rename to tests/ui/unsized/relaxed-bounds-invalid-places.stderr index fb6d37c29660a..3287eb8d1e9d5 100644 --- a/tests/ui/unsized/maybe-bounds-where.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -1,5 +1,5 @@ error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:1:28 + --> $DIR/relaxed-bounds-invalid-places.rs:4:28 | LL | struct S1(T) where (T): ?Sized; | ^^^^^^ @@ -8,7 +8,7 @@ LL | struct S1(T) where (T): ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:4:27 + --> $DIR/relaxed-bounds-invalid-places.rs:7:27 | LL | struct S2(T) where u8: ?Sized; | ^^^^^^ @@ -17,7 +17,7 @@ LL | struct S2(T) where u8: ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:7:35 + --> $DIR/relaxed-bounds-invalid-places.rs:10:35 | LL | struct S3(T) where &'static T: ?Sized; | ^^^^^^ @@ -26,7 +26,7 @@ LL | struct S3(T) where &'static T: ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:12:34 + --> $DIR/relaxed-bounds-invalid-places.rs:15:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | struct S4(T) where for<'a> T: ?Trait<'a>; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:21:21 + --> $DIR/relaxed-bounds-invalid-places.rs:24:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ @@ -44,13 +44,13 @@ LL | fn f() where T: ?Sized {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-bounds-where.rs:12:34 + --> $DIR/relaxed-bounds-invalid-places.rs:15: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 + --> $DIR/relaxed-bounds-invalid-places.rs:19:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ ^^^^^^ @@ -59,7 +59,7 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-bounds-where.rs:16:33 + --> $DIR/relaxed-bounds-invalid-places.rs:19:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ From 87149682951272128601af5725aa607e49744a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 20 Jun 2025 21:39:19 +0200 Subject: [PATCH 5/8] Reword diagnostics about relaxed bounds in invalid contexts --- compiler/rustc_ast_lowering/src/item.rs | 7 +++-- compiler/rustc_ast_lowering/src/lib.rs | 14 +++++---- ...issing-associated_item_or_field_def_ids.rs | 2 +- ...ng-associated_item_or_field_def_ids.stderr | 2 +- ...ing-associated-items-of-undefined-trait.rs | 2 +- ...associated-items-of-undefined-trait.stderr | 2 +- .../feature-gate-more-maybe-bounds.rs | 8 ++--- .../feature-gate-more-maybe-bounds.stderr | 23 ++++++++------- tests/ui/maybe-bounds.rs | 6 ++-- tests/ui/maybe-bounds.stderr | 6 ++-- tests/ui/parser/trait-object-trait-parens.rs | 6 ++-- .../parser/trait-object-trait-parens.stderr | 6 ++-- .../ui/sized-hierarchy/default-supertrait.rs | 6 ++-- .../sized-hierarchy/default-supertrait.stderr | 6 ++-- tests/ui/traits/wf-object/maybe-bound.rs | 12 ++++---- tests/ui/traits/wf-object/maybe-bound.stderr | 10 +++---- tests/ui/traits/wf-object/only-maybe-bound.rs | 2 +- .../traits/wf-object/only-maybe-bound.stderr | 2 +- .../unsized/relaxed-bounds-invalid-places.rs | 14 ++++----- .../relaxed-bounds-invalid-places.stderr | 29 +++++++++++-------- 20 files changed, 85 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4071ad42f81d3..35bf9ac371261 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1874,9 +1874,10 @@ impl<'hir> LoweringContext<'_, 'hir> { bounded_ty, bounds, }) => { - let rbp = match bound_generic_params.is_empty() { - true => RelaxedBoundPolicy::AllowedIfOnTyParam(bounded_ty.id, params), - false => RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::BoundVars), + let rbp = if bound_generic_params.is_empty() { + RelaxedBoundPolicy::AllowedIfOnTyParam(bounded_ty.id, params) + } else { + RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::LateBoundVarsInScope) }; hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params: self.lower_generic_params( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 58a024437dcf9..8faf96a6df2d1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -287,7 +287,7 @@ enum RelaxedBoundPolicy<'a> { enum RelaxedBoundForbiddenReason { TraitObjectTy, SuperTrait, - BoundVars, + LateBoundVarsInScope, } /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, @@ -2085,11 +2085,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match reason { RelaxedBoundForbiddenReason::TraitObjectTy => { - err("`?Trait` is not permitted in trait object types").emit(); + err("relaxed bounds are not permitted in trait object types").emit(); return; } RelaxedBoundForbiddenReason::SuperTrait => { - let mut diag = err("`?Trait` is not permitted in supertraits"); + let mut diag = err("relaxed bounds are not permitted in supertrait bounds"); if let Some(def_id) = trait_ref.trait_def_id() && self.tcx.is_lang_item(def_id, hir::LangItem::Sized) { @@ -2098,12 +2098,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { diag.emit(); return; } - RelaxedBoundForbiddenReason::BoundVars => {} + RelaxedBoundForbiddenReason::LateBoundVarsInScope => {} }; } } - err("`?Trait` bounds are only permitted at the point where a type parameter is declared") + err("this relaxed bound is not permitted here") + .with_note( + "in this context, relaxed bounds are only allowed on \ + type parameters defined by the closest item", + ) .emit(); } diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs index 18c71e5c74429..029ce7d0e7e49 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.rs @@ -2,6 +2,6 @@ fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { //~^ ERROR expected trait, found associated function `Iterator::advance_by` - //~| ERROR `?Trait` is not permitted in trait object types + //~| ERROR relaxed bounds are not permitted in trait object types todo!() } diff --git a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr index 6ec8e01c78d38..3dc7fd78e41e8 100644 --- a/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr +++ b/tests/ui/associated-item/missing-associated_item_or_field_def_ids.stderr @@ -4,7 +4,7 @@ error[E0404]: expected trait, found associated function `Iterator::advance_by` LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a trait -error[E0658]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/missing-associated_item_or_field_def_ids.rs:3:29 | LL | fn main() -> dyn Iterator + ?Iterator::advance_by(usize) { diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs index 9e0a86abb2e0b..bac4e60886772 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.rs @@ -7,5 +7,5 @@ trait Tr { fn main() { let _: dyn Tr + ?Foo; //~^ ERROR: cannot find trait `Foo` in this scope - //~| ERROR: `?Trait` is not permitted in trait object types + //~| ERROR: relaxed bounds are not permitted in trait object types } diff --git a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr index bd83c1a9ea892..3b35c164d37d4 100644 --- a/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr +++ b/tests/ui/associated-types/avoid-getting-associated-items-of-undefined-trait.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `Foo` in this scope LL | let _: dyn Tr + ?Foo; | ^^^ not found in this scope -error[E0658]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/avoid-getting-associated-items-of-undefined-trait.rs:8:21 | LL | let _: dyn Tr + ?Foo; diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs index 6a832744e3ee9..3066967f87e2f 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -2,13 +2,11 @@ trait Trait1 {} auto trait Trait2 {} -trait Trait3: ?Trait1 {} -//~^ ERROR `?Trait` is not permitted in supertraits -trait Trait4 where Self: ?Trait1 {} -//~^ ERROR ?Trait` bounds are only permitted at the point where a type parameter is declared +trait Trait3: ?Trait1 {} //~ ERROR relaxed bounds are not permitted in supertrait bounds +trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitted here fn foo(_: Box) {} -//~^ ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types fn bar(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported //~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index f52532a035b46..e7564542f6328 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -1,4 +1,4 @@ -error[E0658]: `?Trait` is not permitted in supertraits +error[E0658]: relaxed bounds are not permitted in supertrait bounds --> $DIR/feature-gate-more-maybe-bounds.rs:5:15 | LL | trait Trait3: ?Trait1 {} @@ -7,17 +7,18 @@ LL | trait Trait3: ?Trait1 {} = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/feature-gate-more-maybe-bounds.rs:7:26 +error[E0658]: this relaxed bound is not permitted here + --> $DIR/feature-gate-more-maybe-bounds.rs:6:26 | LL | trait Trait4 where Self: ?Trait1 {} | ^^^^^^^ | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/feature-gate-more-maybe-bounds.rs:10:28 +error[E0658]: relaxed bounds are not permitted in trait object types + --> $DIR/feature-gate-more-maybe-bounds.rs:8:28 | LL | fn foo(_: Box) {} | ^^^^^^^ @@ -26,7 +27,7 @@ LL | fn foo(_: Box) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:12:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | LL | fn bar(_: T) {} | ^^^^^^^ ^^^^^^^ @@ -35,31 +36,31 @@ LL | fn bar(_: T) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:12:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | LL | fn bar(_: T) {} | ^^^^^^^ error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:12:21 + --> $DIR/feature-gate-more-maybe-bounds.rs:10:21 | LL | fn bar(_: T) {} | ^^^^^^^ error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:19:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 | LL | fn baz(_ : T) {} | ^^^^^^ ^^^^^^ error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:19:11 + --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 | LL | fn baz(_ : T) {} | ^^^^^^ error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/feature-gate-more-maybe-bounds.rs:19:20 + --> $DIR/feature-gate-more-maybe-bounds.rs:17:20 | LL | fn baz(_ : T) {} | ^^^^^^ diff --git a/tests/ui/maybe-bounds.rs b/tests/ui/maybe-bounds.rs index 02ed45c656f1c..194292a70f275 100644 --- a/tests/ui/maybe-bounds.rs +++ b/tests/ui/maybe-bounds.rs @@ -1,9 +1,9 @@ trait Tr: ?Sized {} -//~^ ERROR `?Trait` is not permitted in supertraits +//~^ ERROR relaxed bounds are not permitted in supertrait bounds type A1 = dyn Tr + (?Sized); -//~^ ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types type A2 = dyn for<'a> Tr + (?Sized); -//~^ ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types fn main() {} diff --git a/tests/ui/maybe-bounds.stderr b/tests/ui/maybe-bounds.stderr index 84a4329ff21d2..5cb377d79824c 100644 --- a/tests/ui/maybe-bounds.stderr +++ b/tests/ui/maybe-bounds.stderr @@ -1,4 +1,4 @@ -error[E0658]: `?Trait` is not permitted in supertraits +error[E0658]: relaxed bounds are not permitted in supertrait bounds --> $DIR/maybe-bounds.rs:1:11 | LL | trait Tr: ?Sized {} @@ -8,7 +8,7 @@ LL | trait Tr: ?Sized {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: traits are `?Sized` by default -error[E0658]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/maybe-bounds.rs:4:20 | LL | type A1 = dyn Tr + (?Sized); @@ -17,7 +17,7 @@ LL | type A1 = dyn Tr + (?Sized); = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/maybe-bounds.rs:6:28 | LL | type A2 = dyn for<'a> Tr + (?Sized); diff --git a/tests/ui/parser/trait-object-trait-parens.rs b/tests/ui/parser/trait-object-trait-parens.rs index 438034bc38aa4..51f0e2de6116f 100644 --- a/tests/ui/parser/trait-object-trait-parens.rs +++ b/tests/ui/parser/trait-object-trait-parens.rs @@ -6,17 +6,17 @@ fn f Trait<'a>)>() {} fn main() { let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; - //~^ ERROR `?Trait` is not permitted in trait object types + //~^ ERROR relaxed bounds are not permitted in trait object types //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let _: Box Trait<'a>) + (Obj)>; - //~^ ERROR `?Trait` is not permitted in trait object types + //~^ ERROR relaxed bounds are not permitted in trait object types //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition let _: Box Trait<'a> + (Obj) + (?Sized)>; - //~^ ERROR `?Trait` is not permitted in trait object types + //~^ ERROR relaxed bounds are not permitted in trait object types //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr index d75352b6811ea..8f8ddeac1c5aa 100644 --- a/tests/ui/parser/trait-object-trait-parens.stderr +++ b/tests/ui/parser/trait-object-trait-parens.stderr @@ -1,4 +1,4 @@ -error[E0658]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:8:24 | LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; @@ -7,7 +7,7 @@ LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:13:16 | LL | let _: Box Trait<'a>) + (Obj)>; @@ -16,7 +16,7 @@ LL | let _: Box Trait<'a>) + (Obj)>; = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/trait-object-trait-parens.rs:18:44 | LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; diff --git a/tests/ui/sized-hierarchy/default-supertrait.rs b/tests/ui/sized-hierarchy/default-supertrait.rs index b25acf9e6ea4f..ab3b28e84db5a 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.rs +++ b/tests/ui/sized-hierarchy/default-supertrait.rs @@ -6,18 +6,18 @@ use std::marker::{MetaSized, PointeeSized}; trait Sized_: Sized { } trait NegSized: ?Sized { } -//~^ ERROR `?Trait` is not permitted in supertraits +//~^ ERROR relaxed bounds are not permitted in supertrait bounds trait MetaSized_: MetaSized { } trait NegMetaSized: ?MetaSized { } -//~^ ERROR `?Trait` is not permitted in supertraits +//~^ ERROR relaxed bounds are not permitted in supertrait bounds trait PointeeSized_: PointeeSized { } trait NegPointeeSized: ?PointeeSized { } -//~^ ERROR `?Trait` is not permitted in supertraits +//~^ ERROR relaxed bounds are not permitted in supertrait bounds trait Bare {} diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr index 0cb4f346a6300..77cb9755d4a1c 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.stderr +++ b/tests/ui/sized-hierarchy/default-supertrait.stderr @@ -1,4 +1,4 @@ -error[E0658]: `?Trait` is not permitted in supertraits +error[E0658]: relaxed bounds are not permitted in supertrait bounds --> $DIR/default-supertrait.rs:8:17 | LL | trait NegSized: ?Sized { } @@ -8,7 +8,7 @@ LL | trait NegSized: ?Sized { } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: traits are `?Sized` by default -error[E0658]: `?Trait` is not permitted in supertraits +error[E0658]: relaxed bounds are not permitted in supertrait bounds --> $DIR/default-supertrait.rs:13:21 | LL | trait NegMetaSized: ?MetaSized { } @@ -17,7 +17,7 @@ LL | trait NegMetaSized: ?MetaSized { } = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in supertraits +error[E0658]: relaxed bounds are not permitted in supertrait bounds --> $DIR/default-supertrait.rs:19:24 | LL | trait NegPointeeSized: ?PointeeSized { } diff --git a/tests/ui/traits/wf-object/maybe-bound.rs b/tests/ui/traits/wf-object/maybe-bound.rs index 17771e976ef3b..917dbd706b59a 100644 --- a/tests/ui/traits/wf-object/maybe-bound.rs +++ b/tests/ui/traits/wf-object/maybe-bound.rs @@ -1,18 +1,18 @@ -// Test that `dyn ... + ?Sized + ...` is okay (though `?Sized` has no effect in trait objects). +// Test that relaxed `Sized` bounds are rejected in trait object types. trait Foo {} type _0 = dyn ?Sized + Foo; -//~^ ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types type _1 = dyn Foo + ?Sized; -//~^ ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types type _2 = dyn Foo + ?Sized + ?Sized; -//~^ ERROR `?Trait` is not permitted in trait object types -//~| ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types +//~| ERROR relaxed bounds are not permitted in trait object types type _3 = dyn ?Sized + Foo; -//~^ ERROR `?Trait` is not permitted in trait object types +//~^ ERROR relaxed bounds are not permitted in trait object types fn main() {} diff --git a/tests/ui/traits/wf-object/maybe-bound.stderr b/tests/ui/traits/wf-object/maybe-bound.stderr index be7afabd0d01d..cacb9dfc84d41 100644 --- a/tests/ui/traits/wf-object/maybe-bound.stderr +++ b/tests/ui/traits/wf-object/maybe-bound.stderr @@ -1,4 +1,4 @@ -error[E0658]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/maybe-bound.rs:5:15 | LL | type _0 = dyn ?Sized + Foo; @@ -7,7 +7,7 @@ LL | type _0 = dyn ?Sized + Foo; = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/maybe-bound.rs:8:21 | LL | type _1 = dyn Foo + ?Sized; @@ -16,7 +16,7 @@ LL | type _1 = dyn Foo + ?Sized; = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/maybe-bound.rs:11:21 | LL | type _2 = dyn Foo + ?Sized + ?Sized; @@ -25,7 +25,7 @@ LL | type _2 = dyn Foo + ?Sized + ?Sized; = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/maybe-bound.rs:11:30 | LL | type _2 = dyn Foo + ?Sized + ?Sized; @@ -34,7 +34,7 @@ LL | type _2 = dyn Foo + ?Sized + ?Sized; = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/maybe-bound.rs:15:15 | LL | type _3 = dyn ?Sized + Foo; diff --git a/tests/ui/traits/wf-object/only-maybe-bound.rs b/tests/ui/traits/wf-object/only-maybe-bound.rs index 3e6db3e997c9b..96360e0331cdb 100644 --- a/tests/ui/traits/wf-object/only-maybe-bound.rs +++ b/tests/ui/traits/wf-object/only-maybe-bound.rs @@ -2,6 +2,6 @@ type _0 = dyn ?Sized; //~^ ERROR at least one trait is required for an object type [E0224] -//~| ERROR ?Trait` is not permitted in trait object types +//~| ERROR relaxed bounds are not permitted in trait object types fn main() {} diff --git a/tests/ui/traits/wf-object/only-maybe-bound.stderr b/tests/ui/traits/wf-object/only-maybe-bound.stderr index 26269476eaaee..d52728e209ec4 100644 --- a/tests/ui/traits/wf-object/only-maybe-bound.stderr +++ b/tests/ui/traits/wf-object/only-maybe-bound.stderr @@ -1,4 +1,4 @@ -error[E0658]: `?Trait` is not permitted in trait object types +error[E0658]: relaxed bounds are not permitted in trait object types --> $DIR/only-maybe-bound.rs:3:15 | LL | type _0 = dyn ?Sized; diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs index ce3f35608bebb..e3a8c6fd0737b 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -1,19 +1,16 @@ // Test that relaxed bounds can only be placed on type parameters defined by the closest item // (ignoring relaxed bounds inside `impl Trait` and in associated type defs here). -struct S1(T) where (T): ?Sized; -//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +struct S1(T) where (T): ?Sized; //~ ERROR this relaxed bound is not permitted here -struct S2(T) where u8: ?Sized; -//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +struct S2(T) where u8: ?Sized; //~ ERROR this relaxed bound is not permitted here -struct S3(T) where &'static T: ?Sized; -//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared +struct S3(T) where &'static T: ?Sized; //~ ERROR this relaxed bound is not permitted here 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 +//~^ ERROR this relaxed bound is not permitted here //~| ERROR relaxing a default bound only does something for `?Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; @@ -21,8 +18,7 @@ struct S5(*const T) where T: ?Trait<'static> + ?Sized; //~| ERROR relaxing a default bound only does something for `?Sized` impl S1 { - fn f() where T: ?Sized {} - //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared + fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here } fn main() { diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr index 3287eb8d1e9d5..d5d96e59068b0 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -1,4 +1,4 @@ -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared +error[E0658]: this relaxed bound is not permitted here --> $DIR/relaxed-bounds-invalid-places.rs:4:28 | LL | struct S1(T) where (T): ?Sized; @@ -6,51 +6,56 @@ LL | struct S1(T) where (T): ?Sized; | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:7:27 +error[E0658]: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:6:27 | LL | struct S2(T) where u8: ?Sized; | ^^^^^^ | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:10:35 +error[E0658]: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:8:35 | LL | struct S3(T) where &'static T: ?Sized; | ^^^^^^ | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:15:34 +error[E0658]: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; | ^^^^^^^^^^ | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error[E0658]: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/relaxed-bounds-invalid-places.rs:24:21 +error[E0658]: this relaxed bound is not permitted here + --> $DIR/relaxed-bounds-invalid-places.rs:21:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ | = help: add `#![feature(more_maybe_bounds)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/relaxed-bounds-invalid-places.rs:15:34 + --> $DIR/relaxed-bounds-invalid-places.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/relaxed-bounds-invalid-places.rs:19:33 + --> $DIR/relaxed-bounds-invalid-places.rs:16:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ ^^^^^^ @@ -59,7 +64,7 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/relaxed-bounds-invalid-places.rs:19:33 + --> $DIR/relaxed-bounds-invalid-places.rs:16:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ From bdc3ffc430278bb148c7856932e8013705e2331e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 19 Jun 2025 18:41:57 +0200 Subject: [PATCH 6/8] Reword diagnostic about relaxing non-`Sized` bound * The phrasing "only does something for" made sense back when this diagnostic was a (hard) warning. Now however, it's simply a hard error and thus completely rules out. * The primary message was way too long * The new wording more closely mirrors the wording we use for applying other bound modifiers (like `const` and `async`) to incompatible traits. * "all other traits are not bound by default" is no longer accurate under Sized Hierarchy. E.g., traits and assoc tys are (currently) bounded by `MetaSized` by default but can't be relaxed using `?MetaSized` (instead, you relax it by adding `PointeeSized`). * I've decided against adding any diagnositic notes or suggestions for now like "trait `Trait` can't be relaxed as it's not bound by default" /which would be incorrect for `MetaSized` and assoc tys as mentioned above) or "consider changing `?MetaSized` to `PointeeSized`" as the Sized Hierarchy impl is still WIP) --- .../src/hir_ty_lowering/bounds.rs | 18 ++++--- .../src/hir_ty_lowering/errors.rs | 47 +++++++++---------- .../feature-gate-more-maybe-bounds.rs | 8 ++-- .../feature-gate-more-maybe-bounds.stderr | 8 ++-- .../impl-trait/opt-out-bound-not-satisfied.rs | 4 +- .../opt-out-bound-not-satisfied.stderr | 4 +- tests/ui/issues/issue-37534.rs | 2 +- tests/ui/issues/issue-37534.stderr | 2 +- tests/ui/issues/issue-87199.rs | 8 ++-- tests/ui/issues/issue-87199.stderr | 8 ++-- tests/ui/sized-hierarchy/default-bound.rs | 4 +- tests/ui/sized-hierarchy/default-bound.stderr | 4 +- .../trait-bounds/maybe-bound-has-path-args.rs | 2 +- .../maybe-bound-has-path-args.stderr | 2 +- .../ui/trait-bounds/maybe-bound-with-assoc.rs | 4 +- .../maybe-bound-with-assoc.stderr | 4 +- tests/ui/trait-bounds/more_maybe_bounds.rs | 25 ++++++++++ .../ui/trait-bounds/more_maybe_bounds.stderr | 20 ++++++++ tests/ui/traits/maybe-polarity-pass.rs | 25 ---------- tests/ui/traits/maybe-polarity-pass.stderr | 20 -------- tests/ui/traits/maybe-polarity-repeated.rs | 4 +- .../ui/traits/maybe-polarity-repeated.stderr | 4 +- .../unsized/relaxed-bounds-invalid-places.rs | 4 +- .../relaxed-bounds-invalid-places.stderr | 4 +- 24 files changed, 118 insertions(+), 117 deletions(-) create mode 100644 tests/ui/trait-bounds/more_maybe_bounds.rs create mode 100644 tests/ui/trait-bounds/more_maybe_bounds.stderr delete mode 100644 tests/ui/traits/maybe-polarity-pass.rs delete mode 100644 tests/ui/traits/maybe-polarity-pass.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 5ec7f0d6438ac..e87ba2486eb3f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -85,17 +85,17 @@ fn search_bounds_for<'tcx>( } } -fn collect_unbounds<'tcx>( +fn collect_relaxed_bounds<'tcx>( hir_bounds: &'tcx [hir::GenericBound<'tcx>], self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, ) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> { - let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); + let mut relaxed_bounds: SmallVec<[_; 1]> = SmallVec::new(); search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) { - unbounds.push(ptr); + relaxed_bounds.push(ptr); } }); - unbounds + relaxed_bounds } fn collect_bounds<'a, 'tcx>( @@ -204,9 +204,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; } } else { - // Report invalid unbounds on sizedness-bounded generic parameters. - let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates); - self.check_and_report_invalid_unbounds_on_param(unbounds); + // Report invalid relaxed bounds. + // FIXME(more_maybe_bounds): This validation function is only called in contexts where + // we perform "sized elaboration". This means, it doesn't get called for e.g., + // trait object types or supertrait bounds! + // Ideally, we would do these checks in `Self::lower_poly_trait_ref`! + let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates); + self.check_and_report_invalid_relaxed_bounds(bounds); } let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 0e79a8918b050..41e374dc472d5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -8,7 +8,7 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef}; +use rustc_hir::{self as hir, HirId, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -35,26 +35,24 @@ use crate::fluent_generated as fluent; use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits. - pub(crate) fn check_and_report_invalid_unbounds_on_param( + /// Check for duplicate relaxed bounds and relaxed bounds of non-default traits. + pub(crate) fn check_and_report_invalid_relaxed_bounds( &self, - unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>, + relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>, ) { let tcx = self.tcx(); - let sized_did = tcx.require_lang_item(LangItem::Sized, DUMMY_SP); - let mut unique_bounds = FxIndexSet::default(); let mut seen_repeat = false; - for unbound in &unbounds { - if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res { - seen_repeat |= !unique_bounds.insert(unbound_def_id); + for bound in &relaxed_bounds { + if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res { + seen_repeat |= !unique_bounds.insert(trait_def_id); } } - if unbounds.len() > 1 { + if relaxed_bounds.len() > 1 { let err = errors::MultipleRelaxedDefaultBounds { - spans: unbounds.iter().map(|ptr| ptr.span).collect(), + spans: relaxed_bounds.iter().map(|ptr| ptr.span).collect(), }; if seen_repeat { @@ -64,24 +62,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; } - for unbound in unbounds { - if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res - && ((did == sized_did) || tcx.is_default_trait(did)) + let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP); + + for bound in relaxed_bounds { + if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res + && (def_id == sized_def_id || tcx.is_default_trait(def_id)) { continue; } - - let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds { - true => "`?Sized` and `experimental_default_bounds`", - false => "`?Sized`", - }; self.dcx().span_err( - unbound.span, - format!( - "relaxing a default bound only does something for {}; all other traits are \ - not bound by default", - unbound_traits - ), + bound.span, + if tcx.sess.opts.unstable_opts.experimental_default_bounds + || tcx.features().more_maybe_bounds() + { + "bound modifier `?` can only be applied to default traits like `Sized`" + } else { + "bound modifier `?` can only be applied to `Sized`" + }, ); } } diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs index 3066967f87e2f..7c9d88462f631 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -9,14 +9,14 @@ fn foo(_: Box) {} //~^ ERROR relaxed bounds are not permitted in trait object types fn bar(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR bound modifier `?` can only be applied to `Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` trait Trait {} // Do not suggest `#![feature(more_maybe_bounds)]` for repetitions fn baz(_ : T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR bound modifier `?` can only be applied to `Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index e7564542f6328..deb4e9113457e 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -35,13 +35,13 @@ LL | fn bar(_: T) {} = help: add `#![feature(more_maybe_bounds)]` 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: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | LL | fn bar(_: T) {} | ^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:10:21 | LL | fn bar(_: T) {} @@ -53,13 +53,13 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i LL | fn baz(_ : T) {} | ^^^^^^ ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 | LL | fn baz(_ : T) {} | ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:17:20 | LL | fn baz(_ : T) {} diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs index 27c493a13bf91..7e0e1eadf9c75 100644 --- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs +++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.rs @@ -3,8 +3,8 @@ use std::future::Future; fn foo() -> impl ?Future { - //~^ ERROR: relaxing a default bound only does something for `?Sized` - //~| ERROR: relaxing a default bound only does something for `?Sized` + //~^ ERROR: bound modifier `?` can only be applied to `Sized` + //~| ERROR: bound modifier `?` can only be applied to `Sized` () } diff --git a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr index dc4314c58ad2f..f99d6a7e5f6d0 100644 --- a/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr +++ b/tests/ui/impl-trait/opt-out-bound-not-satisfied.stderr @@ -1,10 +1,10 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/opt-out-bound-not-satisfied.rs:5:18 | LL | fn foo() -> impl ?Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/opt-out-bound-not-satisfied.rs:5:18 | LL | fn foo() -> impl ?Future { diff --git a/tests/ui/issues/issue-37534.rs b/tests/ui/issues/issue-37534.rs index 09d60b7786b99..63f6479ae2e24 100644 --- a/tests/ui/issues/issue-37534.rs +++ b/tests/ui/issues/issue-37534.rs @@ -1,5 +1,5 @@ struct Foo {} //~^ ERROR expected trait, found derive macro `Hash` -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr index 3219854bc70ce..0860735420301 100644 --- a/tests/ui/issues/issue-37534.stderr +++ b/tests/ui/issues/issue-37534.stderr @@ -9,7 +9,7 @@ help: consider importing this trait instead LL + use std::hash::Hash; | -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-37534.rs:1:15 | LL | struct Foo {} diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs index 4e4e35c6a71e8..dd9dfc74ca352 100644 --- a/tests/ui/issues/issue-87199.rs +++ b/tests/ui/issues/issue-87199.rs @@ -6,12 +6,12 @@ // Check that these function definitions only emit warnings, not errors fn arg(_: T) {} -//~^ ERROR: relaxing a default bound only does something for `?Sized` +//~^ ERROR: bound modifier `?` can only be applied to `Sized` fn ref_arg(_: &T) {} -//~^ ERROR: relaxing a default bound only does something for `?Sized` +//~^ ERROR: bound modifier `?` can only be applied to `Sized` fn ret() -> impl Iterator + ?Send { std::iter::empty() } -//~^ ERROR: relaxing a default bound only does something for `?Sized` -//~| ERROR: relaxing a default bound only does something for `?Sized` +//~^ ERROR: bound modifier `?` can only be applied to `Sized` +//~| ERROR: bound modifier `?` can only be applied to `Sized` // 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 acc4e84779c9c..8a930a3d704c1 100644 --- a/tests/ui/issues/issue-87199.stderr +++ b/tests/ui/issues/issue-87199.stderr @@ -1,22 +1,22 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:8:11 | LL | fn arg(_: T) {} | ^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:10:15 | LL | fn ref_arg(_: &T) {} | ^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:12:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } | ^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/issue-87199.rs:12:40 | LL | fn ret() -> impl Iterator + ?Send { std::iter::empty() } diff --git a/tests/ui/sized-hierarchy/default-bound.rs b/tests/ui/sized-hierarchy/default-bound.rs index 12b2eb2b5c1b4..bbb2c6d96baa8 100644 --- a/tests/ui/sized-hierarchy/default-bound.rs +++ b/tests/ui/sized-hierarchy/default-bound.rs @@ -14,13 +14,13 @@ fn neg_sized() {} fn metasized() {} fn neg_metasized() {} -//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~^ ERROR bound modifier `?` can only be applied to `Sized` fn pointeesized() { } fn neg_pointeesized() { } -//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~^ ERROR bound modifier `?` can only be applied to `Sized` fn main() { diff --git a/tests/ui/sized-hierarchy/default-bound.stderr b/tests/ui/sized-hierarchy/default-bound.stderr index 22f0fa29d3e23..0a4ea6f44d8ed 100644 --- a/tests/ui/sized-hierarchy/default-bound.stderr +++ b/tests/ui/sized-hierarchy/default-bound.stderr @@ -1,10 +1,10 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/default-bound.rs:16:21 | LL | fn neg_metasized() {} | ^^^^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/default-bound.rs:22:24 | LL | fn neg_pointeesized() { } diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs index e5abcae5d219b..14a2667049775 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs @@ -2,6 +2,6 @@ trait Trait {} fn test::Trait>() {} //~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args` -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr index dc55b26c9183c..bf968b05af085 100644 --- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr +++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr @@ -1,4 +1,4 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/maybe-bound-has-path-args.rs:3:12 | LL | fn test::Trait>() {} diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs index 9127c2de16d5e..e123f18474d1c 100644 --- a/tests/ui/trait-bounds/maybe-bound-with-assoc.rs +++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.rs @@ -2,11 +2,11 @@ trait HasAssoc { type Assoc; } fn hasassoc>() {} -//~^ ERROR relaxing a default bound +//~^ ERROR bound modifier `?` can only be applied to `Sized` trait NoAssoc {} fn noassoc>() {} -//~^ ERROR relaxing a default bound +//~^ ERROR bound modifier `?` can only be applied to `Sized` //~| ERROR associated type `Missing` not found for `NoAssoc` fn main() {} diff --git a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr index 36a1e0ade2063..b2ae0584aff91 100644 --- a/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr +++ b/tests/ui/trait-bounds/maybe-bound-with-assoc.stderr @@ -1,10 +1,10 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/maybe-bound-with-assoc.rs:4:16 | LL | fn hasassoc>() {} | ^^^^^^^^^^^^^^^^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/maybe-bound-with-assoc.rs:8:15 | LL | fn noassoc>() {} diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs new file mode 100644 index 0000000000000..d70c9bb158cc4 --- /dev/null +++ b/tests/ui/trait-bounds/more_maybe_bounds.rs @@ -0,0 +1,25 @@ +// FIXME(more_maybe_bounds): This used to be a check-pass test before rustc started to reject +// relaxed bounds of *non-default* traits. Therefore, the original test intention has been lost. +#![feature(auto_traits, more_maybe_bounds, negative_impls)] + +trait Trait1 {} +auto trait Trait2 {} + +trait Trait3 : ?Trait1 {} +trait Trait4 where Self: Trait1 {} + +fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {} +fn bar(_: &T) {} +//~^ ERROR bound modifier `?` can only be applied to default traits like `Sized` +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` + +struct S; +impl !Trait2 for S {} +impl Trait1 for S {} +impl Trait3 for S {} + +fn main() { + foo(Box::new(S)); + bar(&S); +} diff --git a/tests/ui/trait-bounds/more_maybe_bounds.stderr b/tests/ui/trait-bounds/more_maybe_bounds.stderr new file mode 100644 index 0000000000000..6041ca65823ee --- /dev/null +++ b/tests/ui/trait-bounds/more_maybe_bounds.stderr @@ -0,0 +1,20 @@ +error: bound modifier `?` can only be applied to default traits like `Sized` + --> $DIR/more_maybe_bounds.rs:12:20 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +error: bound modifier `?` can only be applied to default traits like `Sized` + --> $DIR/more_maybe_bounds.rs:12:30 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +error: bound modifier `?` can only be applied to default traits like `Sized` + --> $DIR/more_maybe_bounds.rs:12:40 + | +LL | fn bar(_: &T) {} + | ^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/traits/maybe-polarity-pass.rs b/tests/ui/traits/maybe-polarity-pass.rs deleted file mode 100644 index 1ccd52bc1694a..0000000000000 --- a/tests/ui/traits/maybe-polarity-pass.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![feature(auto_traits)] -#![feature(more_maybe_bounds)] -#![feature(negative_impls)] - -trait Trait1 {} -auto trait Trait2 {} - -trait Trait3 : ?Trait1 {} -trait Trait4 where Self: Trait1 {} - -fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {} -fn bar(_: &T) {} -//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - -struct S; -impl !Trait2 for S {} -impl Trait1 for S {} -impl Trait3 for S {} - -fn main() { - foo(Box::new(S)); - bar(&S); -} diff --git a/tests/ui/traits/maybe-polarity-pass.stderr b/tests/ui/traits/maybe-polarity-pass.stderr deleted file mode 100644 index 1f378dd665ae6..0000000000000 --- a/tests/ui/traits/maybe-polarity-pass.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:12:20 - | -LL | fn bar(_: &T) {} - | ^^^^^^^ - -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:12:30 - | -LL | fn bar(_: &T) {} - | ^^^^^^^ - -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/maybe-polarity-pass.rs:12:40 - | -LL | fn bar(_: &T) {} - | ^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/tests/ui/traits/maybe-polarity-repeated.rs b/tests/ui/traits/maybe-polarity-repeated.rs index fd1ef567b3eab..962e3d5dbc5cc 100644 --- a/tests/ui/traits/maybe-polarity-repeated.rs +++ b/tests/ui/traits/maybe-polarity-repeated.rs @@ -3,7 +3,7 @@ trait Trait {} fn foo(_: T) {} //~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default -//~| ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` fn main() {} diff --git a/tests/ui/traits/maybe-polarity-repeated.stderr b/tests/ui/traits/maybe-polarity-repeated.stderr index 4fa1dc45bda85..de16c14718005 100644 --- a/tests/ui/traits/maybe-polarity-repeated.stderr +++ b/tests/ui/traits/maybe-polarity-repeated.stderr @@ -4,13 +4,13 @@ error[E0203]: type parameter has more than one relaxed default bound, only one i LL | fn foo(_: T) {} | ^^^^^^ ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to default traits like `Sized` --> $DIR/maybe-polarity-repeated.rs:4:11 | LL | fn foo(_: T) {} | ^^^^^^ -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to default traits like `Sized` --> $DIR/maybe-polarity-repeated.rs:4:20 | LL | fn foo(_: T) {} diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs index e3a8c6fd0737b..c81fd0dfe3026 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -11,11 +11,11 @@ trait Trait<'a> {} struct S4(T) where for<'a> T: ?Trait<'a>; //~^ ERROR this relaxed bound is not permitted here -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; //~^ ERROR type parameter has more than one relaxed default bound -//~| ERROR relaxing a default bound only does something for `?Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` impl S1 { fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr index d5d96e59068b0..416a35f7fa5ae 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -48,7 +48,7 @@ LL | fn f() where T: ?Sized {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item -error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/relaxed-bounds-invalid-places.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; @@ -63,7 +63,7 @@ LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; = help: add `#![feature(more_maybe_bounds)]` 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: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default +error: bound modifier `?` can only be applied to `Sized` --> $DIR/relaxed-bounds-invalid-places.rs:16:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; From e6cadca7d38332277ca6587082d793de5a5ca8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 20 Jun 2025 20:21:01 +0200 Subject: [PATCH 7/8] Don't reject *multiple* relaxed bounds, reject *duplicate* ones. Having multiple relaxed bounds like `?Sized + ?Iterator` is actually *fine*. We actually want to reject *duplicate* relaxed bounds like `?Sized + ?Sized` because these most certainly represent a user error. Note that this doesn't mean that we accept more code because a bound like `?Iterator` is still invalid as it's not relaxing a *default* trait and the only way to define / use more default bounds is under the experimental and internal feature `more_maybe_bounds` plus `lang_items` plus unstable flag `-Zexperimental-default-bounds`. Ultimately, this simply *reframes* the diagnostic. The scope of `more_maybe_bounds` / `-Zexperimental-default-bounds` remains unchanged as well. --- compiler/rustc_hir_analysis/messages.ftl | 3 -- compiler/rustc_hir_analysis/src/errors.rs | 7 --- .../src/hir_ty_lowering/errors.rs | 24 +++++----- .../feature-gate-more-maybe-bounds.rs | 10 +--- .../feature-gate-more-maybe-bounds.stderr | 32 +------------ .../trait-bounds/duplicate-relaxed-bounds.rs | 22 +++++++++ .../duplicate-relaxed-bounds.stderr | 47 +++++++++++++++++++ ...7441.rs => fix-dyn-sized-fn-param-sugg.rs} | 25 +++++----- ...err => fix-dyn-sized-fn-param-sugg.stderr} | 40 ++++++++-------- tests/ui/traits/maybe-polarity-repeated.rs | 9 ---- .../ui/traits/maybe-polarity-repeated.stderr | 21 --------- .../unsized/relaxed-bounds-invalid-places.rs | 3 +- .../relaxed-bounds-invalid-places.stderr | 16 ++----- 13 files changed, 119 insertions(+), 140 deletions(-) create mode 100644 tests/ui/trait-bounds/duplicate-relaxed-bounds.rs create mode 100644 tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr rename tests/ui/trait-bounds/{bad-suggestionf-for-repeated-unsized-bound-127441.rs => fix-dyn-sized-fn-param-sugg.rs} (51%) rename tests/ui/trait-bounds/{bad-suggestionf-for-repeated-unsized-bound-127441.stderr => fix-dyn-sized-fn-param-sugg.stderr} (80%) delete mode 100644 tests/ui/traits/maybe-polarity-repeated.rs delete mode 100644 tests/ui/traits/maybe-polarity-repeated.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index bd2252c1bf8fd..a41903d26d6a5 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -371,9 +371,6 @@ hir_analysis_missing_type_params = *[other] parameters } must be specified on the object type -hir_analysis_multiple_relaxed_default_bounds = - type parameter has more than one relaxed default bound, only one is supported - hir_analysis_must_be_name_of_associated_function = must be a name of an associated function hir_analysis_must_implement_not_function = not a function diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 318aaab50f4d4..915f5a375e24c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -277,13 +277,6 @@ pub(crate) struct CopyImplOnTypeWithDtor { pub span: Span, } -#[derive(Diagnostic)] -#[diag(hir_analysis_multiple_relaxed_default_bounds, code = E0203)] -pub(crate) struct MultipleRelaxedDefaultBounds { - #[primary_span] - pub spans: Vec, -} - #[derive(Diagnostic)] #[diag(hir_analysis_copy_impl_on_non_adt, code = E0206)] pub(crate) struct CopyImplOnNonAdt { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 41e374dc472d5..cc484e2915857 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -42,24 +42,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) { let tcx = self.tcx(); - let mut unique_bounds = FxIndexSet::default(); - let mut seen_repeat = false; + let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default(); + for bound in &relaxed_bounds { if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res { - seen_repeat |= !unique_bounds.insert(trait_def_id); + grouped_bounds.entry(trait_def_id).or_default().push(bound.span); } } - if relaxed_bounds.len() > 1 { - let err = errors::MultipleRelaxedDefaultBounds { - spans: relaxed_bounds.iter().map(|ptr| ptr.span).collect(), - }; - - if seen_repeat { - tcx.dcx().emit_err(err); - } else if !tcx.features().more_maybe_bounds() { - tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit(); - }; + for (trait_def_id, spans) in grouped_bounds { + if spans.len() > 1 { + let name = tcx.item_name(trait_def_id); + self.dcx() + .struct_span_err(spans, format!("duplicate relaxed `{name}` bounds")) + .with_code(E0203) + .emit(); + } } let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP); diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs index 7c9d88462f631..9c727ae3aad4c 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.rs @@ -8,15 +8,7 @@ trait Trait4 where Self: ?Trait1 {} //~ ERROR this relaxed bound is not permitte fn foo(_: Box) {} //~^ ERROR relaxed bounds are not permitted in trait object types fn bar(_: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR bound modifier `?` can only be applied to `Sized` -//~| ERROR bound modifier `?` can only be applied to `Sized` - -trait Trait {} -// Do not suggest `#![feature(more_maybe_bounds)]` for repetitions -fn baz(_ : T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR bound modifier `?` can only be applied to `Sized` +//~^ ERROR bound modifier `?` can only be applied to `Sized` //~| ERROR bound modifier `?` can only be applied to `Sized` fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr index deb4e9113457e..d01d9cbef3adc 100644 --- a/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr @@ -26,15 +26,6 @@ LL | fn foo(_: Box) {} = help: add `#![feature(more_maybe_bounds)]` 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[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 - | -LL | fn bar(_: T) {} - | ^^^^^^^ ^^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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: bound modifier `?` can only be applied to `Sized` --> $DIR/feature-gate-more-maybe-bounds.rs:10:11 | @@ -47,25 +38,6 @@ error: bound modifier `?` can only be applied to `Sized` LL | fn bar(_: T) {} | ^^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 - | -LL | fn baz(_ : T) {} - | ^^^^^^ ^^^^^^ - -error: bound modifier `?` can only be applied to `Sized` - --> $DIR/feature-gate-more-maybe-bounds.rs:17:11 - | -LL | fn baz(_ : T) {} - | ^^^^^^ - -error: bound modifier `?` can only be applied to `Sized` - --> $DIR/feature-gate-more-maybe-bounds.rs:17:20 - | -LL | fn baz(_ : T) {} - | ^^^^^^ - -error: aborting due to 9 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0203, E0658. -For more information about an error, try `rustc --explain E0203`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs new file mode 100644 index 0000000000000..a1681ddec77b0 --- /dev/null +++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.rs @@ -0,0 +1,22 @@ +fn dupes() {} +//~^ ERROR duplicate relaxed `Sized` bounds +//~| ERROR duplicate relaxed `Iterator` bounds +//~| ERROR bound modifier `?` can only be applied to `Sized` +//~| ERROR bound modifier `?` can only be applied to `Sized` + +trait Trait { + // We used to say "type parameter has more than one relaxed default bound" + // even on *associated types* like here. Test that we no longer do that. + type Type: ?Sized + ?Sized; + //~^ ERROR duplicate relaxed `Sized` bounds + //~| ERROR duplicate relaxed `Sized` bounds +} + +// We used to emit an additional error about "multiple relaxed default bounds". +// However, multiple relaxed bounds are actually *fine* if they're distinct. +// Ultimately, we still reject this because `Sized` is +// the only (stable) default trait, so we're fine. +fn not_dupes() {} +//~^ ERROR bound modifier `?` can only be applied to `Sized` + +fn main() {} diff --git a/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr new file mode 100644 index 0000000000000..ea236789e3227 --- /dev/null +++ b/tests/ui/trait-bounds/duplicate-relaxed-bounds.stderr @@ -0,0 +1,47 @@ +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/duplicate-relaxed-bounds.rs:1:13 + | +LL | fn dupes() {} + | ^^^^^^ ^^^^^^ + +error[E0203]: duplicate relaxed `Iterator` bounds + --> $DIR/duplicate-relaxed-bounds.rs:1:31 + | +LL | fn dupes() {} + | ^^^^^^^^^ ^^^^^^^^^ + +error: bound modifier `?` can only be applied to `Sized` + --> $DIR/duplicate-relaxed-bounds.rs:1:31 + | +LL | fn dupes() {} + | ^^^^^^^^^ + +error: bound modifier `?` can only be applied to `Sized` + --> $DIR/duplicate-relaxed-bounds.rs:1:43 + | +LL | fn dupes() {} + | ^^^^^^^^^ + +error: bound modifier `?` can only be applied to `Sized` + --> $DIR/duplicate-relaxed-bounds.rs:18:26 + | +LL | fn not_dupes() {} + | ^^^^^^^^^ + +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/duplicate-relaxed-bounds.rs:10:16 + | +LL | type Type: ?Sized + ?Sized; + | ^^^^^^ ^^^^^^ + +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/duplicate-relaxed-bounds.rs:10:16 + | +LL | type Type: ?Sized + ?Sized; + | ^^^^^^ ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0203`. diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs similarity index 51% rename from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs rename to tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs index e6d7f74880fb2..1aa36207bc3ea 100644 --- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs +++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.rs @@ -1,39 +1,38 @@ -// Regression test for #127441 - -// Tests that we make the correct suggestion -// in case there are more than one `?Sized` -// bounds on a function parameter +// Test that we emit a correct structured suggestions for dynamically sized ("maybe unsized") +// function parameters. +// We used to emit a butchered suggestion if duplicate relaxed `Sized` bounds were present. +// issue: . use std::fmt::Debug; fn foo1(a: T) {} -//~^ ERROR he size for values of type `T` cannot be known at compilation time +//~^ ERROR the size for values of type `T` cannot be known at compilation time fn foo2(a: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `T` cannot be known at compilation time fn foo3(a: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR he size for values of type `T` cannot be known at compilation time +//~^ ERROR duplicate relaxed `Sized` bounds +//~| ERROR the size for values of type `T` cannot be known at compilation time fn foo4(a: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `T` cannot be known at compilation time fn foo5(_: impl ?Sized) {} //~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time fn foo6(_: impl ?Sized + ?Sized) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim fn foo7(_: impl ?Sized + ?Sized + Debug) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time fn foo8(_: impl ?Sized + Debug + ?Sized ) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported +//~^ ERROR duplicate relaxed `Sized` bounds //~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time fn main() {} diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr similarity index 80% rename from tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr rename to tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr index 363f52d6df8d5..7a9c2f043ac41 100644 --- a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr +++ b/tests/ui/trait-bounds/fix-dyn-sized-fn-param-sugg.stderr @@ -1,41 +1,41 @@ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:12 | LL | fn foo2(a: T) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:12 | LL | fn foo3(a: T) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:12 | LL | fn foo4(a: T) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:17 | LL | fn foo6(_: impl ?Sized + ?Sized) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:17 | LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} | ^^^^^^ ^^^^^^ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17 +error[E0203]: duplicate relaxed `Sized` bounds + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:17 | LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} | ^^^^^^ ^^^^^^ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:23 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:8:23 | LL | fn foo1(a: T) {} | - ^ doesn't have a size known at compile-time @@ -54,7 +54,7 @@ LL | fn foo1(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:32 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:11:32 | LL | fn foo2(a: T) {} | - ^ doesn't have a size known at compile-time @@ -73,7 +73,7 @@ LL | fn foo2(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:40 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:15:40 | LL | fn foo3(a: T) {} | - ^ doesn't have a size known at compile-time @@ -92,7 +92,7 @@ LL | fn foo3(a: &T) {} | + error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:41 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:19:41 | LL | fn foo4(a: T) {} | - ^ doesn't have a size known at compile-time @@ -111,7 +111,7 @@ LL | fn foo4(a: &T) {} | + error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:23:12 | LL | fn foo5(_: impl ?Sized) {} | ^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | fn foo5(_: &impl ?Sized) {} | + error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:26:12 | LL | fn foo6(_: impl ?Sized + ?Sized) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | fn foo6(_: &impl ?Sized + ?Sized) {} | + error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:30:12 | LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -171,7 +171,7 @@ LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {} | + error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time - --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:12 + --> $DIR/fix-dyn-sized-fn-param-sugg.rs:34:12 | LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/maybe-polarity-repeated.rs b/tests/ui/traits/maybe-polarity-repeated.rs deleted file mode 100644 index 962e3d5dbc5cc..0000000000000 --- a/tests/ui/traits/maybe-polarity-repeated.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(more_maybe_bounds)] - -trait Trait {} -fn foo(_: T) {} -//~^ ERROR type parameter has more than one relaxed default bound, only one is supported -//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` -//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` - -fn main() {} diff --git a/tests/ui/traits/maybe-polarity-repeated.stderr b/tests/ui/traits/maybe-polarity-repeated.stderr deleted file mode 100644 index de16c14718005..0000000000000 --- a/tests/ui/traits/maybe-polarity-repeated.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0203]: type parameter has more than one relaxed default bound, only one is supported - --> $DIR/maybe-polarity-repeated.rs:4:11 - | -LL | fn foo(_: T) {} - | ^^^^^^ ^^^^^^ - -error: bound modifier `?` can only be applied to default traits like `Sized` - --> $DIR/maybe-polarity-repeated.rs:4:11 - | -LL | fn foo(_: T) {} - | ^^^^^^ - -error: bound modifier `?` can only be applied to default traits like `Sized` - --> $DIR/maybe-polarity-repeated.rs:4:20 - | -LL | fn foo(_: T) {} - | ^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0203`. diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs index c81fd0dfe3026..95ba0089a67ac 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs @@ -14,8 +14,7 @@ struct S4(T) where for<'a> T: ?Trait<'a>; //~| ERROR bound modifier `?` can only be applied to `Sized` struct S5(*const T) where T: ?Trait<'static> + ?Sized; -//~^ ERROR type parameter has more than one relaxed default bound -//~| ERROR bound modifier `?` can only be applied to `Sized` +//~^ ERROR bound modifier `?` can only be applied to `Sized` impl S1 { fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr index 416a35f7fa5ae..e2621b86c933f 100644 --- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr +++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr @@ -39,7 +39,7 @@ LL | struct S4(T) where for<'a> T: ?Trait<'a>; = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item error[E0658]: this relaxed bound is not permitted here - --> $DIR/relaxed-bounds-invalid-places.rs:21:21 + --> $DIR/relaxed-bounds-invalid-places.rs:20:21 | LL | fn f() where T: ?Sized {} | ^^^^^^ @@ -54,22 +54,12 @@ error: bound modifier `?` can only be applied to `Sized` 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/relaxed-bounds-invalid-places.rs:16:33 - | -LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; - | ^^^^^^^^^^^^^^^ ^^^^^^ - | - = help: add `#![feature(more_maybe_bounds)]` 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: bound modifier `?` can only be applied to `Sized` --> $DIR/relaxed-bounds-invalid-places.rs:16:33 | LL | struct S5(*const T) where T: ?Trait<'static> + ?Sized; | ^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0203, E0658. -For more information about an error, try `rustc --explain E0203`. +For more information about this error, try `rustc --explain E0658`. From 04dad4ee8a1ab859b18f157763a8f3ac7ceaf16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 20 Jun 2025 23:13:11 +0200 Subject: [PATCH 8/8] HIR ty lowering: Validate `PointeeSized` bounds --- .../src/hir_ty_lowering/bounds.rs | 36 +++----------- .../src/hir_ty_lowering/mod.rs | 48 ++++++++++--------- .../ui/sized-hierarchy/pointee-validation.rs | 14 ++++++ .../sized-hierarchy/pointee-validation.stderr | 37 ++++++++++++++ 4 files changed, 83 insertions(+), 52 deletions(-) create mode 100644 tests/ui/sized-hierarchy/pointee-validation.rs create mode 100644 tests/ui/sized-hierarchy/pointee-validation.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index e87ba2486eb3f..de18e3e87b69c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -6,7 +6,7 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{AmbigArg, LangItem, PolyTraitRef}; +use rustc_hir::{AmbigArg, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -124,13 +124,13 @@ fn collect_sizedness_bounds<'tcx>( self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, span: Span, ) -> CollectedSizednessBounds { - let sized_did = tcx.require_lang_item(LangItem::Sized, span); + let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did); - let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); + let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span); let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did); - let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); + let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did); CollectedSizednessBounds { sized, meta_sized, pointee_sized } @@ -151,24 +151,6 @@ fn add_trait_bound<'tcx>( } impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Skip `PointeeSized` bounds. - /// - /// `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there - /// is actually the absence of any bounds. This avoids limitations around non-global where - /// clauses being preferred over item bounds (where `PointeeSized` bounds would be - /// proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is - /// added to some items. - pub(crate) fn should_skip_sizedness_bound<'hir>( - &self, - bound: &'hir hir::GenericBound<'tcx>, - ) -> bool { - bound - .trait_ref() - .and_then(|tr| tr.trait_def_id()) - .map(|did| self.tcx().is_lang_item(did, LangItem::PointeeSized)) - .unwrap_or(false) - } - /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type. /// /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit @@ -188,8 +170,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) { let tcx = self.tcx(); - let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); - let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); + let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span); + let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); // If adding sizedness bounds to a trait, then there are some relevant early exits if let Some(trait_did) = trait_did { @@ -230,7 +212,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else { // If there are no explicit sizedness bounds on a parameter then add a default // `Sized` bound. - let sized_did = tcx.require_lang_item(LangItem::Sized, span); + let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); add_trait_bound(tcx, bounds, self_ty, sized_did, span); } } @@ -465,10 +447,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { 'tcx: 'hir, { for hir_bound in hir_bounds { - if self.should_skip_sizedness_bound(hir_bound) { - continue; - } - // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`, // we skip over any traits that don't define the given associated type. if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index b11d37fe1cf9a..1fc65aded3d06 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -758,6 +758,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, ) -> GenericArgCountResult { + let tcx = self.tcx(); + // We use the *resolved* bound vars later instead of the HIR ones since the former // also include the bound vars of the overarching predicate if applicable. let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } = @@ -765,6 +767,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let hir::TraitBoundModifiers { constness, polarity } = modifiers; let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); + + let (polarity, bounds) = match polarity { + rustc_ast::BoundPolarity::Positive + if tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized) => + { + // Skip `PointeeSized` bounds. + // + // `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there + // is actually the absence of any bounds. This avoids limitations around non-global where + // clauses being preferred over item bounds (where `PointeeSized` bounds would be + // proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is + // added to some items. + (ty::PredicatePolarity::Positive, &mut Vec::new()) + } + rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds), + rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds), + // FIXME(fmease): This is super hacky! `Option` is also sad. + rustc_ast::BoundPolarity::Maybe(_) => { + (ty::PredicatePolarity::Positive, &mut Vec::new()) + } + }; + let trait_segment = trait_ref.path.segments.last().unwrap(); let _ = self.prohibit_generic_args( @@ -781,7 +805,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(self_ty), ); - let tcx = self.tcx(); let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); debug!(?bound_vars); @@ -792,27 +815,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?poly_trait_ref); - let polarity = match polarity { - rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive, - rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative, - rustc_ast::BoundPolarity::Maybe(_) => { - // Validate associated type at least. We may want to reject these - // outright in the future... - for constraint in trait_segment.args().constraints { - let _ = self.lower_assoc_item_constraint( - trait_ref.hir_ref_id, - poly_trait_ref, - constraint, - &mut Default::default(), - &mut Default::default(), - constraint.span, - predicate_filter, - ); - } - return arg_count; - } - }; - // We deal with const conditions later. match predicate_filter { PredicateFilter::All @@ -915,7 +917,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Don't register any associated item constraints for negative bounds, // since we should have emitted an error for them earlier, and they // would not be well-formed! - if polarity != ty::PredicatePolarity::Positive { + if polarity == ty::PredicatePolarity::Negative { self.dcx().span_delayed_bug( constraint.span, "negative trait bounds should not have assoc item constraints", diff --git a/tests/ui/sized-hierarchy/pointee-validation.rs b/tests/ui/sized-hierarchy/pointee-validation.rs new file mode 100644 index 0000000000000..35ece5047bec2 --- /dev/null +++ b/tests/ui/sized-hierarchy/pointee-validation.rs @@ -0,0 +1,14 @@ +// Test that despite us dropping `PointeeSized` bounds during HIR ty lowering +// we still validate it first. +// issue: +#![feature(sized_hierarchy)] + +use std::marker::PointeeSized; + +struct Test where (): const PointeeSized<(), Undefined = ()>; +//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied +//~| ERROR associated type `Undefined` not found for `PointeeSized` +//~| ERROR `const` can only be applied to `#[const_trait]` traits +//~| ERROR const trait impls are experimental + +fn main() {} diff --git a/tests/ui/sized-hierarchy/pointee-validation.stderr b/tests/ui/sized-hierarchy/pointee-validation.stderr new file mode 100644 index 0000000000000..ee748a6d3e031 --- /dev/null +++ b/tests/ui/sized-hierarchy/pointee-validation.stderr @@ -0,0 +1,37 @@ +error[E0658]: const trait impls are experimental + --> $DIR/pointee-validation.rs:8:23 + | +LL | struct Test where (): const PointeeSized<(), Undefined = ()>; + | ^^^^^ + | + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` 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[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/pointee-validation.rs:8:29 + | +LL | struct Test where (): const PointeeSized<(), Undefined = ()>; + | ^^^^^^^^^^^^-------------------- help: remove the unnecessary generics + | | + | expected 0 generic arguments + +error: `const` can only be applied to `#[const_trait]` traits + --> $DIR/pointee-validation.rs:8:23 + | +LL | struct Test where (): const PointeeSized<(), Undefined = ()>; + | ^^^^^ can't be applied to `PointeeSized` + | +note: `PointeeSized` can't be used with `const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/marker.rs:LL:COL + +error[E0220]: associated type `Undefined` not found for `PointeeSized` + --> $DIR/pointee-validation.rs:8:46 + | +LL | struct Test where (): const PointeeSized<(), Undefined = ()>; + | ^^^^^^^^^ associated type `Undefined` not found + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0220, E0658. +For more information about an error, try `rustc --explain E0107`.