Skip to content

Commit b75feaa

Browse files
authored
Unrolled build for #147734
Rollup merge of #147734 - fmease:tighten-relaxed, r=lcnr Further tighten up relaxed bounds Follow-up to #142693, #135331 and #135841. Fixes #143122. * Reject relaxed bounds `?Trait` in the bounds of trait aliases. Just like `trait Trait {}` doesn't mean `trait Trait: Sized {}` and we therefore reject `trait Trait: ?Sized {}`, `trait Trait =;` (sic!) doesn't mean `trait Trait = Sized;` (never did!) and as a logical consequence `trait Trait = ?Sized;` is meaningless and should be forbidden. * Don't permit `?Sized` in more places (e.g., supertrait bounds, trait object types) if feature `more_maybe_bounds` is enabled. That internal feature is only meant to allow the user to define & use *new* default traits (that have fewer rules to follow for now to ease experimentation). * Unconditionally check that the `Trait` in `?Trait` is a default trait. Previously, we would only perform this check in selected places which was very brittle and led to bugs slipping through. * Slightly improve diagnostics.
2 parents fd847d4 + 65814c8 commit b75feaa

30 files changed

+473
-316
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
@@ -297,6 +297,7 @@ enum RelaxedBoundPolicy<'a> {
297297
enum RelaxedBoundForbiddenReason {
298298
TraitObjectTy,
299299
SuperTrait,
300+
TraitAlias,
300301
AssocTyBounds,
301302
LateBoundVarsInScope,
302303
}
@@ -2086,12 +2087,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20862087
span: Span,
20872088
rbp: RelaxedBoundPolicy<'_>,
20882089
) {
2089-
// Even though feature `more_maybe_bounds` bypasses the given policy and (currently) enables
2090-
// relaxed bounds in every conceivable position[^1], we don't want to advertise it to the user
2091-
// (via a feature gate) since it's super internal. Besides this, it'd be quite distracting.
2090+
// Even though feature `more_maybe_bounds` enables the user to relax all default bounds
2091+
// other than `Sized` in a lot more positions (thereby bypassing the given policy), we don't
2092+
// want to advertise it to the user (via a feature gate error) since it's super internal.
20922093
//
2093-
// [^1]: Strictly speaking, this is incorrect (at the very least for `Sized`) because it's
2094-
// no longer fully consistent with default trait elaboration in HIR ty lowering.
2094+
// FIXME(more_maybe_bounds): Moreover, if we actually were to add proper default traits
2095+
// (like a hypothetical `Move` or `Leak`) we would want to validate the location according
2096+
// to default trait elaboration in HIR ty lowering (which depends on the specific trait in
2097+
// question: E.g., `?Sized` & `?Move` most likely won't be allowed in all the same places).
20952098

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

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

Lines changed: 49 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,53 @@ 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 tcx = self.tcx();
339+
340+
if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res
341+
&& (tcx.is_lang_item(def_id, hir::LangItem::Sized) || tcx.is_default_trait(def_id))
342+
{
343+
return;
344+
}
345+
346+
self.dcx().span_err(
347+
span,
348+
if tcx.sess.opts.unstable_opts.experimental_default_bounds
349+
|| tcx.features().more_maybe_bounds()
350+
{
351+
"bound modifier `?` can only be applied to default traits"
352+
} else {
353+
"bound modifier `?` can only be applied to `Sized`"
354+
},
355+
);
356+
}
357+
313358
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
314359
///
315360
/// ### 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(

0 commit comments

Comments
 (0)