Skip to content

Commit 9ed9a73

Browse files
Auto merge of #147734 - fmease:tighten-relaxed, r=<try>
Further tighten up relaxed bounds
2 parents 28d0a4a + af9009f commit 9ed9a73

26 files changed

+291
-227
lines changed

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
426426
|this| {
427427
this.lower_param_bounds(
428428
bounds,
429-
RelaxedBoundPolicy::Allowed,
429+
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::TraitAlias),
430430
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
431431
)
432432
},

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ enum RelaxedBoundPolicy<'a> {
296296
enum RelaxedBoundForbiddenReason {
297297
TraitObjectTy,
298298
SuperTrait,
299+
TraitAlias,
299300
AssocTyBounds,
300301
LateBoundVarsInScope,
301302
}
@@ -2085,12 +2086,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20852086
span: Span,
20862087
rbp: RelaxedBoundPolicy<'_>,
20872088
) {
2088-
// Even though feature `more_maybe_bounds` bypasses the given policy and (currently) enables
2089-
// relaxed bounds in every conceivable position[^1], we don't want to advertise it to the user
2090-
// (via a feature gate) since it's super internal. Besides this, it'd be quite distracting.
2089+
// Even though feature `more_maybe_bounds` enables the user to relax all default bounds
2090+
// other than `Sized` in a lot more positions (thereby bypassing the given policy, we don't
2091+
// want to advertise it to the user (via a feature gate error) since it's super internal.
20912092
//
2092-
// [^1]: Strictly speaking, this is incorrect (at the very least for `Sized`) because it's
2093-
// no longer fully consistent with default trait elaboration in HIR ty lowering.
2093+
// FIXME(more_maybe_bounds): Moreover, if we actually were to add new proper default traits
2094+
// (like the hypothetical `Move`) we want to properly validate the location according to
2095+
// default trait elaboration in HIR ty lowering (which depends on the specific trait in
2096+
// question: E.g., `?Sized` & `?Move` most likely won't be allowed in all the same places).
20942097

20952098
match rbp {
20962099
RelaxedBoundPolicy::Allowed => return,
@@ -2103,33 +2106,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21032106
}
21042107
}
21052108
RelaxedBoundPolicy::Forbidden(reason) => {
2109+
let gate = |context, subject| {
2110+
let extended = self.tcx.features().more_maybe_bounds();
2111+
let is_sized = trait_ref
2112+
.trait_def_id()
2113+
.is_some_and(|def_id| self.tcx.is_lang_item(def_id, hir::LangItem::Sized));
2114+
2115+
if extended && !is_sized {
2116+
return;
2117+
}
2118+
2119+
let prefix = if extended { "`Sized` " } else { "" };
2120+
let mut diag = self.dcx().struct_span_err(
2121+
span,
2122+
format!("relaxed {prefix}bounds are not permitted in {context}"),
2123+
);
2124+
if is_sized {
2125+
diag.note(format!(
2126+
"{subject} are not implicitly bounded by `Sized`, \
2127+
so there is nothing to relax"
2128+
));
2129+
}
2130+
diag.emit();
2131+
};
2132+
21062133
match reason {
21072134
RelaxedBoundForbiddenReason::TraitObjectTy => {
2108-
if self.tcx.features().more_maybe_bounds() {
2109-
return;
2110-
}
2111-
2112-
self.dcx().span_err(
2113-
span,
2114-
"relaxed bounds are not permitted in trait object types",
2115-
);
2135+
gate("trait object types", "trait object types");
21162136
return;
21172137
}
21182138
RelaxedBoundForbiddenReason::SuperTrait => {
2119-
if self.tcx.features().more_maybe_bounds() {
2120-
return;
2121-
}
2122-
2123-
let mut diag = self.dcx().struct_span_err(
2124-
span,
2125-
"relaxed bounds are not permitted in supertrait bounds",
2126-
);
2127-
if let Some(def_id) = trait_ref.trait_def_id()
2128-
&& self.tcx.is_lang_item(def_id, hir::LangItem::Sized)
2129-
{
2130-
diag.note("traits are `?Sized` by default");
2131-
}
2132-
diag.emit();
2139+
gate("supertrait bounds", "traits");
2140+
return;
2141+
}
2142+
RelaxedBoundForbiddenReason::TraitAlias => {
2143+
gate("trait alias bounds", "trait aliases");
21332144
return;
21342145
}
21352146
RelaxedBoundForbiddenReason::AssocTyBounds
@@ -2142,7 +2153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21422153
.struct_span_err(span, "this relaxed bound is not permitted here")
21432154
.with_note(
21442155
"in this context, relaxed bounds are only allowed on \
2145-
type parameters defined by the closest item",
2156+
type parameters defined on the closest item",
21462157
)
21472158
.emit();
21482159
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
202202
// where we are guaranteed to catch *all* bounds like in
203203
// `Self::lower_poly_trait_ref`. List of concrete issues:
204204
// FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait
205-
// bounds or associated type bounds (ATB)!
206-
// FIXME(trait_alias, #143122): We don't call it for the RHS. Arguably however,
207-
// AST lowering should reject them outright.
205+
// bounds, trait alias bounds, assoc type bounds (ATB)!
208206
let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
209-
self.check_and_report_invalid_relaxed_bounds(bounds);
207+
self.reject_duplicate_relaxed_bounds(bounds);
210208
}
211209

212210
let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
@@ -310,6 +308,58 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
310308
!self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any()
311309
}
312310

311+
fn reject_duplicate_relaxed_bounds(&self, relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>) {
312+
let tcx = self.tcx();
313+
314+
let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
315+
316+
for bound in &relaxed_bounds {
317+
if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
318+
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
319+
}
320+
}
321+
322+
for (trait_def_id, spans) in grouped_bounds {
323+
if spans.len() > 1 {
324+
let name = tcx.item_name(trait_def_id);
325+
self.dcx()
326+
.struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
327+
.with_code(E0203)
328+
.emit();
329+
}
330+
}
331+
}
332+
333+
pub(crate) fn require_bound_to_relax_default_trait(
334+
&self,
335+
trait_ref: hir::TraitRef<'_>,
336+
span: Span,
337+
) {
338+
let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res else { return };
339+
let tcx = self.tcx();
340+
341+
if tcx.is_lang_item(def_id, hir::LangItem::Sized) || tcx.is_default_trait(def_id) {
342+
// FIXME(fmease): Debug-assert that the trait doesn't have any generic parameters
343+
// (except `Self`) or associated items since we wouldn't be able to
344+
// wfcheck args & constraints passed to it.
345+
// E.g., `?BadDefaultTrait<Vec<str>`.
346+
// NOTE: Alternatively / additionally, introduce a validation step for
347+
// traits marked `#[default_trait]` in AST validation / lowering.
348+
return;
349+
}
350+
351+
self.dcx().span_err(
352+
span,
353+
if tcx.sess.opts.unstable_opts.experimental_default_bounds
354+
|| tcx.features().more_maybe_bounds()
355+
{
356+
"bound modifier `?` can only be applied to default traits"
357+
} else {
358+
"bound modifier `?` can only be applied to `Sized`"
359+
},
360+
);
361+
}
362+
313363
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
314364
///
315365
/// ### Examples

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_errors::{
88
};
99
use rustc_hir::def::{CtorOf, DefKind, Res};
1010
use rustc_hir::def_id::DefId;
11-
use rustc_hir::{self as hir, HirId, PolyTraitRef};
11+
use rustc_hir::{self as hir, HirId};
1212
use rustc_middle::bug;
1313
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
1414
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -35,52 +35,6 @@ use crate::fluent_generated as fluent;
3535
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
3636

3737
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
38-
/// Check for duplicate relaxed bounds and relaxed bounds of non-default traits.
39-
pub(crate) fn check_and_report_invalid_relaxed_bounds(
40-
&self,
41-
relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
42-
) {
43-
let tcx = self.tcx();
44-
45-
let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
46-
47-
for bound in &relaxed_bounds {
48-
if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
49-
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
50-
}
51-
}
52-
53-
for (trait_def_id, spans) in grouped_bounds {
54-
if spans.len() > 1 {
55-
let name = tcx.item_name(trait_def_id);
56-
self.dcx()
57-
.struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
58-
.with_code(E0203)
59-
.emit();
60-
}
61-
}
62-
63-
let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP);
64-
65-
for bound in relaxed_bounds {
66-
if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res
67-
&& (def_id == sized_def_id || tcx.is_default_trait(def_id))
68-
{
69-
continue;
70-
}
71-
self.dcx().span_err(
72-
bound.span,
73-
if tcx.sess.opts.unstable_opts.experimental_default_bounds
74-
|| tcx.features().more_maybe_bounds()
75-
{
76-
"bound modifier `?` can only be applied to default traits like `Sized`"
77-
} else {
78-
"bound modifier `?` can only be applied to `Sized`"
79-
},
80-
);
81-
}
82-
}
83-
8438
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
8539
/// the type parameter's name as a placeholder.
8640
pub(crate) fn report_missing_type_params(

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
767767

768768
// We use the *resolved* bound vars later instead of the HIR ones since the former
769769
// also include the bound vars of the overarching predicate if applicable.
770-
let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } =
770+
let hir::PolyTraitRef { bound_generic_params: _, modifiers, trait_ref, span } =
771771
*poly_trait_ref;
772772
let hir::TraitBoundModifiers { constness, polarity } = modifiers;
773773

@@ -791,6 +791,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
791791
rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds),
792792
rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds),
793793
rustc_ast::BoundPolarity::Maybe(_) => {
794+
self.require_bound_to_relax_default_trait(trait_ref, span);
795+
794796
(ty::PredicatePolarity::Positive, &mut Vec::new())
795797
}
796798
};

compiler/rustc_middle/src/ty/context.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,9 +1782,7 @@ impl<'tcx> TyCtxt<'tcx> {
17821782
}
17831783

17841784
pub fn is_default_trait(self, def_id: DefId) -> bool {
1785-
self.default_traits()
1786-
.iter()
1787-
.any(|&default_trait| self.lang_items().get(default_trait) == Some(def_id))
1785+
self.default_traits().iter().any(|&default_trait| self.is_lang_item(def_id, default_trait))
17881786
}
17891787

17901788
/// Returns a range of the start/end indices specified with the

tests/rustdoc-ui/doc-alias-assoc-const.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![feature(trait_alias)]
2-
31
pub struct Foo;
42

53
pub trait Bar {

tests/rustdoc-ui/doc-alias-assoc-const.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block
2-
--> $DIR/doc-alias-assoc-const.rs:10:11
2+
--> $DIR/doc-alias-assoc-const.rs:8:11
33
|
44
LL | #[doc(alias = "CONST_BAZ")]
55
| ^^^^^^^^^^^^^^^^^^^

tests/ui/feature-gates/feature-gate-more-maybe-bounds.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ error: this relaxed bound is not permitted here
1010
LL | trait Trait4 where Self: ?Trait1 {}
1111
| ^^^^^^^
1212
|
13-
= note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
13+
= note: in this context, relaxed bounds are only allowed on type parameters defined on the closest item
1414

1515
error: relaxed bounds are not permitted in trait object types
1616
--> $DIR/feature-gate-more-maybe-bounds.rs:8:28

tests/ui/parser/trait-object-trait-parens.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,24 @@ error: relaxed bounds are not permitted in trait object types
33
|
44
LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
55
| ^^^^^^^^
6+
|
7+
= note: trait object types are not implicitly bounded by `Sized`, so there is nothing to relax
68

79
error: relaxed bounds are not permitted in trait object types
810
--> $DIR/trait-object-trait-parens.rs:13:16
911
|
1012
LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
1113
| ^^^^^^
14+
|
15+
= note: trait object types are not implicitly bounded by `Sized`, so there is nothing to relax
1216

1317
error: relaxed bounds are not permitted in trait object types
1418
--> $DIR/trait-object-trait-parens.rs:18:44
1519
|
1620
LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
1721
| ^^^^^^^^
22+
|
23+
= note: trait object types are not implicitly bounded by `Sized`, so there is nothing to relax
1824

1925
warning: trait objects without an explicit `dyn` are deprecated
2026
--> $DIR/trait-object-trait-parens.rs:8:16

0 commit comments

Comments
 (0)