Skip to content

Commit d6ac697

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 be51f99 commit d6ac697

File tree

65 files changed

+821
-172
lines changed

Some content is hidden

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

65 files changed

+821
-172
lines changed

compiler/rustc_data_structures/src/lib.rs

+1
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

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ fn associated_type_bounds<'tcx>(
5050
hir_bounds,
5151
None,
5252
span,
53+
assoc_item_def_id,
5354
);
5455
}
5556
// `ConstIfConst` is only interested in `~const` bounds.
@@ -346,6 +347,7 @@ fn opaque_type_bounds<'tcx>(
346347
hir_bounds,
347348
None,
348349
span,
350+
opaque_def_id,
349351
);
350352
}
351353
//`ConstIfConst` is only interested in `~const` bounds.

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+1
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

+53-14
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,19 @@ use crate::hir_ty_lowering::{
2525

2626
#[derive(Debug, Default)]
2727
struct CollectedBound {
28+
constness: bool,
2829
/// `Trait`
29-
positive: bool,
30+
positive: Option<Span>,
3031
/// `?Trait`
31-
maybe: bool,
32+
maybe: Option<Span>,
3233
/// `!Trait`
33-
negative: bool,
34+
negative: Option<Span>,
3435
}
3536

3637
impl CollectedBound {
3738
/// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered.
3839
fn any(&self) -> bool {
39-
self.positive || self.maybe || self.negative
40+
self.positive.is_some() || self.maybe.is_some() || self.negative.is_some()
4041
}
4142
}
4243

@@ -84,17 +85,23 @@ fn collect_sizedness_bounds<'tcx>(
8485
unbounds.push(ptr);
8586
}
8687

88+
let has_constness = matches!(
89+
ptr.modifiers.constness,
90+
hir::BoundConstness::Always(_) | hir::BoundConstness::Maybe(_)
91+
);
92+
8793
let collect_into = match ptr.trait_ref.path.res {
8894
Res::Def(DefKind::Trait, did) if did == sized_did => &mut sized,
8995
Res::Def(DefKind::Trait, did) if did == meta_sized_did => &mut meta_sized,
9096
Res::Def(DefKind::Trait, did) if did == pointee_sized_did => &mut pointee_sized,
9197
_ => continue,
9298
};
9399

100+
collect_into.constness = has_constness;
94101
match ptr.modifiers.polarity {
95-
hir::BoundPolarity::Maybe(_) => collect_into.maybe = true,
96-
hir::BoundPolarity::Negative(_) => collect_into.negative = true,
97-
hir::BoundPolarity::Positive => collect_into.positive = true,
102+
hir::BoundPolarity::Maybe(_) => collect_into.maybe = Some(hir_bound.span()),
103+
hir::BoundPolarity::Negative(_) => collect_into.negative = Some(hir_bound.span()),
104+
hir::BoundPolarity::Positive => collect_into.positive = Some(hir_bound.span()),
98105
}
99106
}
100107
};
@@ -183,21 +190,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
183190
let tcx = self.tcx();
184191

185192
let span = tcx.def_span(trait_did);
193+
let sized_did = tcx.require_lang_item(LangItem::Sized, Some(span));
186194
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, Some(span));
187195
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, Some(span));
188196

197+
let trait_hir_id = tcx.local_def_id_to_hir_id(trait_did);
189198
let trait_did = trait_did.to_def_id();
190199
if trait_did == pointee_sized_did {
191200
// Never add a default supertrait to `PointeeSized`.
192201
return;
193202
}
194203

195204
let (collected, _unbounds) = collect_sizedness_bounds(tcx, hir_bounds, None, span);
196-
if !collected.any() && trait_did != pointee_sized_did {
197-
// If there are no explicit sizedness bounds then add a default `const MetaSized`
198-
// supertrait.
205+
if !collected.any() && !tcx.sess.edition().at_least_edition_future() {
206+
// Emit migration lint when the feature is enabled.
207+
self.emit_implicit_const_meta_sized_supertrait_lint(trait_hir_id, span);
208+
209+
// If it is not Edition Future and there are no explicit sizedness bounds then add a
210+
// default `const MetaSized` supertrait.
199211
add_trait_predicate(tcx, bounds, self_ty, meta_sized_did, span);
200212
add_host_effect_predicate(tcx, bounds, self_ty, meta_sized_did, span);
213+
} else if let Some(bound_span) = collected.sized.positive
214+
&& !collected.sized.constness
215+
&& !tcx.sess.edition().at_least_edition_future()
216+
{
217+
// Emit migration lint when the feature is enabled.
218+
self.emit_sized_to_const_sized_lint(trait_hir_id, bound_span);
219+
220+
// If it is not Edition Future then `Sized` is equivalent to writing `const Sized`.
221+
add_trait_predicate(tcx, bounds, self_ty, sized_did, bound_span);
222+
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, bound_span);
201223
}
202224

203225
// See doc comment on `adjust_sizedness_predicates`.
@@ -214,6 +236,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
214236
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
215237
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
216238
span: Span,
239+
trait_did: LocalDefId,
217240
) {
218241
let tcx = self.tcx();
219242

@@ -223,21 +246,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
223246

224247
let (collected, unbounds) =
225248
collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
226-
self.check_and_report_invalid_unbounds_on_param(unbounds);
249+
let trait_hir_id = tcx.local_def_id_to_hir_id(trait_did);
250+
self.check_and_report_invalid_unbounds_on_param(trait_hir_id, unbounds);
227251

228-
if (collected.sized.maybe || collected.sized.negative)
229-
&& !collected.sized.positive
252+
if (collected.sized.maybe.is_some() || collected.sized.negative.is_some())
253+
&& !collected.sized.positive.is_some()
230254
&& !collected.meta_sized.any()
231255
&& !collected.pointee_sized.any()
232256
{
233257
// `?Sized` is equivalent to `const MetaSized` (but only add the bound if there aren't
234258
// any other explicit ones)
235259
add_trait_predicate(tcx, bounds, self_ty, meta_sized_did, span);
236260
add_host_effect_predicate(tcx, bounds, self_ty, meta_sized_did, span);
261+
} else if let Some(bound_span) = collected.sized.positive
262+
&& !collected.sized.constness
263+
&& !tcx.sess.edition().at_least_edition_future()
264+
{
265+
// Emit migration lint when the feature is enabled.
266+
self.emit_sized_to_const_sized_lint(trait_hir_id, bound_span);
267+
268+
// Replace `Sized` with `const Sized`.
269+
add_trait_predicate(tcx, bounds, self_ty, sized_did, bound_span);
270+
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, bound_span);
237271
} else if !collected.any() {
238272
// If there are no explicit sizedness bounds then add a default `const Sized` bound.
239273
add_trait_predicate(tcx, bounds, self_ty, sized_did, span);
240-
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, span);
274+
275+
if !tcx.sess.edition().at_least_edition_future() {
276+
self.emit_default_sized_to_const_sized_lint(trait_hir_id, span);
277+
278+
add_host_effect_predicate(tcx, bounds, self_ty, sized_did, span);
279+
}
241280
}
242281

243282
// See doc comment on `adjust_sizedness_predicates`.

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+101-5
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_meta_sized_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_lint_defs/src/builtin.rs

+39
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+
}

compiler/rustc_middle/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#![allow(rustc::potential_query_instability)]
3131
#![allow(rustc::untranslatable_diagnostic)]
3232
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
33+
#![cfg_attr(not(bootstrap), allow(sized_hierarchy_migration))]
3334
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
3435
#![doc(rust_logo)]
3536
#![feature(allocator_api)]

compiler/rustc_serialize/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// tidy-alphabetical-start
44
#![allow(internal_features)]
55
#![allow(rustc::internal)]
6+
#![cfg_attr(not(bootstrap), allow(sized_hierarchy_migration))]
67
#![cfg_attr(test, feature(test))]
78
#![doc(
89
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",

compiler/rustc_smir/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![allow(internal_features)]
1111
#![allow(rustc::usage_of_ty_tykind)]
1212
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
13+
#![cfg_attr(not(bootstrap), allow(sized_hierarchy_migration))]
1314
#![doc(
1415
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
1516
test(attr(allow(unused_variables), deny(warnings)))

tests/ui/const-generics/unused-type-param-suggestion.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![crate_type="lib"]
2+
#![allow(sized_hierarchy_migration)]
23
#![feature(sized_hierarchy)]
34

45
struct S<N>;

0 commit comments

Comments
 (0)