Skip to content

Commit 3a85235

Browse files
committed
hir_analysis: edition migration
Implement the edition migration required by these changes - `?Sized` becoming `const MetaSized`, `Sized` becoming `const Sized` and a `const MetaSized` supertrait.
1 parent fac657d commit 3a85235

File tree

64 files changed

+760
-166
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+760
-166
lines changed

compiler/rustc_data_structures/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![allow(internal_features)]
1111
#![allow(rustc::default_hash_types)]
1212
#![allow(rustc::potential_query_instability)]
13+
#![cfg_attr(not(bootstrap), allow(sized_hierarchy_migration))]
1314
#![deny(unsafe_op_in_unsafe_fn)]
1415
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
1516
#![doc(rust_logo)]

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ fn associated_type_bounds<'tcx>(
5151
hir_bounds,
5252
None,
5353
span,
54+
assoc_item_def_id,
5455
);
5556
}
5657
// `ConstIfConst` is only interested in `~const` bounds.
@@ -347,6 +348,7 @@ fn opaque_type_bounds<'tcx>(
347348
hir_bounds,
348349
None,
349350
span,
351+
opaque_def_id,
350352
);
351353
}
352354
//`ConstIfConst` is only interested in `~const` bounds.

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
230230
&[],
231231
Some((param.def_id, hir_generics.predicates)),
232232
param.span,
233+
def_id,
233234
);
234235
trace!(?bounds);
235236
predicates.extend(bounds);

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,19 @@ use crate::hir_ty_lowering::{
2323

2424
#[derive(Debug, Default)]
2525
struct CollectedBound {
26+
constness: bool,
2627
/// `Trait`
27-
positive: bool,
28+
positive: Option<Span>,
2829
/// `?Trait`
29-
maybe: bool,
30+
maybe: Option<Span>,
3031
/// `!Trait`
31-
negative: bool,
32+
negative: Option<Span>,
3233
}
3334

3435
impl CollectedBound {
3536
/// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered.
3637
fn any(&self) -> bool {
37-
self.positive || self.maybe || self.negative
38+
self.positive.is_some() || self.maybe.is_some() || self.negative.is_some()
3839
}
3940
}
4041

@@ -82,27 +83,37 @@ fn collect_sizedness_bounds<'tcx>(
8283
unbounds.push(ptr);
8384
}
8485

86+
let has_constness = matches!(
87+
ptr.modifiers.constness,
88+
hir::BoundConstness::Always(_) | hir::BoundConstness::Maybe(_)
89+
);
90+
8591
if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_did) {
92+
sized.constness = has_constness;
8693
match ptr.modifiers.polarity {
87-
hir::BoundPolarity::Maybe(_) => sized.maybe = true,
88-
hir::BoundPolarity::Negative(_) => sized.negative = true,
89-
hir::BoundPolarity::Positive => sized.positive = true,
94+
hir::BoundPolarity::Maybe(_) => sized.maybe = Some(hir_bound.span()),
95+
hir::BoundPolarity::Negative(_) => sized.negative = Some(hir_bound.span()),
96+
hir::BoundPolarity::Positive => sized.positive = Some(hir_bound.span()),
9097
}
9198
}
9299

93100
if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, metasized_did) {
101+
metasized.constness = has_constness;
94102
match ptr.modifiers.polarity {
95-
hir::BoundPolarity::Maybe(_) => metasized.maybe = true,
96-
hir::BoundPolarity::Negative(_) => metasized.negative = true,
97-
hir::BoundPolarity::Positive => metasized.positive = true,
103+
hir::BoundPolarity::Maybe(_) => metasized.maybe = Some(hir_bound.span()),
104+
hir::BoundPolarity::Negative(_) => metasized.negative = Some(hir_bound.span()),
105+
hir::BoundPolarity::Positive => metasized.positive = Some(hir_bound.span()),
98106
}
99107
}
100108

101109
if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, pointeesized_did) {
110+
pointeesized.constness = has_constness;
102111
match ptr.modifiers.polarity {
103-
hir::BoundPolarity::Maybe(_) => pointeesized.maybe = true,
104-
hir::BoundPolarity::Negative(_) => pointeesized.negative = true,
105-
hir::BoundPolarity::Positive => pointeesized.positive = true,
112+
hir::BoundPolarity::Maybe(_) => pointeesized.maybe = Some(hir_bound.span()),
113+
hir::BoundPolarity::Negative(_) => {
114+
pointeesized.negative = Some(hir_bound.span())
115+
}
116+
hir::BoundPolarity::Positive => pointeesized.positive = Some(hir_bound.span()),
106117
}
107118
}
108119
}
@@ -201,21 +212,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
201212
let tcx = self.tcx();
202213

203214
let span = tcx.def_span(trait_did);
215+
let sized_did = tcx.require_lang_item(LangItem::Sized, Some(span));
204216
let metasized_did = tcx.require_lang_item(LangItem::MetaSized, Some(span));
205217
let pointeesized_did = tcx.require_lang_item(LangItem::PointeeSized, Some(span));
206218

219+
let trait_hir_id = tcx.local_def_id_to_hir_id(trait_did);
207220
let trait_did = trait_did.to_def_id();
208221
if trait_did == pointeesized_did {
209222
// Never add a default supertrait to `PointeeSized`.
210223
return;
211224
}
212225

213226
let (collected, _unbounds) = collect_sizedness_bounds(tcx, hir_bounds, None, span);
214-
if !collected.any() && trait_did != pointeesized_did {
215-
// If there are no explicit sizedness bounds then add a default `const MetaSized`
216-
// supertrait.
227+
if !collected.any() && !tcx.sess.edition().at_least_edition_future() {
228+
// Emit migration lint when the feature is enabled.
229+
self.emit_implicit_const_metasized_supertrait_lint(trait_hir_id, span);
230+
231+
// If it is not Edition Future and there are no explicit sizedness bounds then add a
232+
// default `const MetaSized` supertrait.
217233
add_trait_predicate(tcx, bounds, self_ty, metasized_did, span);
218234
add_host_effect_predicate(tcx, bounds, self_ty, metasized_did, span);
235+
} else if let Some(bound_span) = collected.sized.positive
236+
&& !collected.sized.constness
237+
&& !tcx.sess.edition().at_least_edition_future()
238+
{
239+
// Emit migration lint when the feature is enabled.
240+
self.emit_sized_to_const_sized_lint(trait_hir_id, bound_span);
241+
242+
// If it is not Edition Future then `Sized` is equivalent to writing `const Sized`.
243+
add_trait_predicate(tcx, bounds, self_ty, sized_did, bound_span);
244+
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, bound_span);
219245
}
220246

221247
// See doc comment on `adjust_sizedness_predicates`.
@@ -232,6 +258,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
232258
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
233259
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
234260
span: Span,
261+
trait_did: LocalDefId,
235262
) {
236263
let tcx = self.tcx();
237264

@@ -241,21 +268,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
241268

242269
let (collected, unbounds) =
243270
collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
244-
self.check_and_report_invalid_unbounds_on_param(unbounds);
271+
let trait_hir_id = tcx.local_def_id_to_hir_id(trait_did);
272+
self.check_and_report_invalid_unbounds_on_param(trait_hir_id, unbounds);
245273

246-
if (collected.sized.maybe || collected.sized.negative)
247-
&& !collected.sized.positive
274+
if (collected.sized.maybe.is_some() || collected.sized.negative.is_some())
275+
&& !collected.sized.positive.is_some()
248276
&& !collected.metasized.any()
249277
&& !collected.pointeesized.any()
250278
{
251279
// `?Sized` is equivalent to `const MetaSized` (but only add the bound if there aren't
252280
// any other explicit ones)
253281
add_trait_predicate(tcx, bounds, self_ty, metasized_did, span);
254282
add_host_effect_predicate(tcx, bounds, self_ty, metasized_did, span);
283+
} else if let Some(bound_span) = collected.sized.positive
284+
&& !collected.sized.constness
285+
&& !tcx.sess.edition().at_least_edition_future()
286+
{
287+
// Emit migration lint when the feature is enabled.
288+
self.emit_sized_to_const_sized_lint(trait_hir_id, bound_span);
289+
290+
// Replace `Sized` with `const Sized`.
291+
add_trait_predicate(tcx, bounds, self_ty, sized_did, bound_span);
292+
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, bound_span);
255293
} else if !collected.any() {
256294
// If there are no explicit sizedness bounds then add a default `const Sized` bound.
257295
add_trait_predicate(tcx, bounds, self_ty, sized_did, span);
258-
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, span);
296+
297+
if !tcx.sess.edition().at_least_edition_future() {
298+
self.emit_default_sized_to_const_sized_lint(trait_hir_id, span);
299+
300+
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, span);
301+
}
259302
}
260303

261304
// See doc comment on `adjust_sizedness_predicates`.

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ use rustc_errors::{
77
};
88
use rustc_hir::def::{CtorOf, DefKind, Res};
99
use rustc_hir::def_id::DefId;
10-
use rustc_hir::{self as hir, LangItem, PolyTraitRef};
10+
use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef};
1111
use rustc_middle::bug;
1212
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
1313
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
1414
use rustc_middle::ty::{
1515
self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
1616
suggest_constraining_type_param,
1717
};
18+
use rustc_session::lint;
1819
use rustc_session::parse::feature_err;
1920
use rustc_span::edit_distance::find_best_match_for_name;
2021
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
@@ -32,9 +33,10 @@ use crate::fluent_generated as fluent;
3233
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
3334

3435
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
35-
/// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits.
36+
/// Check for multiple relaxed default bounds and relaxed bounds.
3637
pub(crate) fn check_and_report_invalid_unbounds_on_param(
3738
&self,
39+
trait_hir_id: HirId,
3840
unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
3941
) {
4042
let tcx = self.tcx();
@@ -62,12 +64,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
6264
}
6365

6466
for unbound in unbounds {
65-
if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res
66-
&& (did == sized_did)
67-
{
67+
let is_sized = matches!(
68+
unbound.trait_ref.path.res,
69+
Res::Def(DefKind::Trait, did) if did == sized_did
70+
);
71+
if is_sized && !tcx.features().sized_hierarchy() {
6872
continue;
6973
}
7074

75+
if tcx.features().sized_hierarchy() && is_sized {
76+
tcx.node_span_lint(
77+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
78+
trait_hir_id,
79+
unbound.span,
80+
|lint| {
81+
lint.primary_message(
82+
"`?Sized` bound relaxations are being migrated to `const MetaSized`",
83+
);
84+
lint.span_suggestion(
85+
unbound.span,
86+
"replace `?Sized` with `const MetaSized`",
87+
"const MetaSized",
88+
Applicability::MachineApplicable,
89+
);
90+
},
91+
);
92+
return;
93+
}
94+
95+
// There was a `?Trait` bound, but it was not `?Sized`.
7196
self.dcx().span_err(
7297
unbound.span,
7398
"relaxing a default bound only does something for `?Sized`; all other traits \
@@ -76,6 +101,77 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
76101
}
77102
}
78103

104+
/// Emit lint adding a `const MetaSized` supertrait as part of sized hierarchy migration.
105+
pub(crate) fn emit_implicit_const_metasized_supertrait_lint(
106+
&self,
107+
trait_hir_id: HirId,
108+
span: Span,
109+
) {
110+
let tcx = self.tcx();
111+
if tcx.features().sized_hierarchy() {
112+
tcx.node_span_lint(
113+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
114+
trait_hir_id,
115+
span,
116+
|lint| {
117+
lint.primary_message(
118+
"a `const MetaSized` supertrait is required to maintain backwards \
119+
compatibility",
120+
);
121+
lint.span_suggestion(
122+
span.shrink_to_hi(),
123+
"add an explicit `const MetaSized` supertrait",
124+
": const MetaSized",
125+
Applicability::MachineApplicable,
126+
);
127+
},
128+
);
129+
}
130+
}
131+
132+
/// Emit lint changing `Sized` bounds to `const MetaSized` bounds as part of sized hierarchy
133+
/// migration.
134+
pub(crate) fn emit_sized_to_const_sized_lint(&self, trait_hir_id: HirId, span: Span) {
135+
let tcx = self.tcx();
136+
if tcx.features().sized_hierarchy() {
137+
tcx.node_span_lint(
138+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
139+
trait_hir_id,
140+
span,
141+
|lint| {
142+
lint.primary_message("`Sized` bounds are being migrated to `const Sized`");
143+
lint.span_suggestion(
144+
span,
145+
"replace `Sized` with `const Sized`",
146+
"const Sized",
147+
Applicability::MachineApplicable,
148+
);
149+
},
150+
);
151+
}
152+
}
153+
154+
/// Emit lint adding `const MetaSized` bound as part of sized hierarchy migration.
155+
pub(crate) fn emit_default_sized_to_const_sized_lint(&self, trait_hir_id: HirId, span: Span) {
156+
let tcx = self.tcx();
157+
if tcx.features().sized_hierarchy() {
158+
tcx.node_span_lint(
159+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
160+
trait_hir_id,
161+
span,
162+
|lint| {
163+
lint.primary_message("default bounds are being migrated to `const Sized`");
164+
lint.span_suggestion(
165+
span.shrink_to_hi(),
166+
"add `const Sized`",
167+
": const Sized",
168+
Applicability::MachineApplicable,
169+
);
170+
},
171+
);
172+
}
173+
}
174+
79175
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
80176
/// the type parameter's name as a placeholder.
81177
pub(crate) fn complain_about_missing_type_params(

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11561156
}
11571157
});
11581158
for param in generics.params {
1159+
debug!(?param, ?param.span, ?cause_span, ?sized_pred);
11591160
if param.span == cause_span && sized_pred {
11601161
let (sp, sugg) = match param.colon_span {
11611162
Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ declare_lint_pass! {
9797
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
9898
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
9999
SINGLE_USE_LIFETIMES,
100+
SIZED_HIERARCHY_MIGRATION,
100101
SOFT_UNSTABLE,
101102
STABLE_FEATURES,
102103
SUPERTRAIT_ITEM_SHADOWING_DEFINITION,
@@ -5125,3 +5126,41 @@ declare_lint! {
51255126
reference: "issue #116558 <https://github.com/rust-lang/rust/issues/116558>",
51265127
};
51275128
}
5129+
5130+
declare_lint! {
5131+
/// The `sized_hierarchy_migration` lint detects uses of the `Sized` trait which must be
5132+
/// migrated with the introduction of a hierarchy of sizedness traits.
5133+
///
5134+
/// ### Example
5135+
/// ```rust,edition_2024,compile_fail
5136+
/// #![feature(sized_hierarchy)]
5137+
/// #![deny(sized_hierarchy_migration)]
5138+
///
5139+
/// pub fn foo<T: ?Sized>() {}
5140+
///
5141+
/// pub trait Foo {}
5142+
///
5143+
/// pub fn bar<T>() {}
5144+
///
5145+
/// pub fn qux<T: Sized>() {}
5146+
/// ```
5147+
///
5148+
/// {{produces}}
5149+
///
5150+
/// ### Explanation
5151+
/// In order to preserve backwards compatibility when a hierarchy of sizedness traits is
5152+
/// introduced, various migrations are necessary:
5153+
///
5154+
/// - `Sized` becomes `const Sized`
5155+
/// - `?Sized` becomes `const MetaSized`
5156+
/// - Traits have a `const MetaSized` supertrait
5157+
///
5158+
/// See [RFC #3729](https://github.com/rust-lang/rfcs/pull/3729) for more details.
5159+
pub SIZED_HIERARCHY_MIGRATION,
5160+
Warn,
5161+
"new sized traits are being introduced which require migration to maintain backwards compat",
5162+
@future_incompatible = FutureIncompatibleInfo {
5163+
reason: FutureIncompatibilityReason::EditionError(Edition::EditionFuture),
5164+
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-future/sized-hierarchy.html>",
5165+
};
5166+
}

0 commit comments

Comments
 (0)