Skip to content

Commit 00d9f41

Browse files
Put normalization outside of lit_to_const query
1 parent 9587fd7 commit 00d9f41

File tree

4 files changed

+155
-171
lines changed

4 files changed

+155
-171
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+115-119
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
128128

129129
if let Some(generics) = node.generics() {
130130
for param in generics.params {
131-
check_param_wf(tcx, param)
131+
check_param_wf(tcx, param, def_id.def_id)
132132
}
133133
}
134134
}
@@ -846,140 +846,136 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
846846
check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig);
847847
}
848848

849-
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
849+
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>, owner_id: LocalDefId) {
850850
match param.kind {
851851
// We currently only check wf of const params here.
852852
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
853853

854854
// Const parameters are well formed if their type is structural match.
855855
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
856-
let mut ty = tcx.type_of(param.def_id);
857-
while let ty::Projection(ty::ProjectionTy { substs, item_def_id }) = ty.kind() {
858-
let binder_ty = tcx.bound_type_of(*item_def_id);
859-
ty = binder_ty.subst(tcx, substs);
860-
}
856+
enter_wf_checking_ctxt(tcx, param.span, owner_id, |wfcx| {
857+
let ty = tcx.type_of(param.def_id);
858+
let ty = wfcx.normalize(hir_ty.span, None, ty);
859+
860+
if tcx.features().adt_const_params {
861+
if let Some(non_structural_match_ty) =
862+
traits::search_for_adt_const_param_violation(param.span, tcx, ty)
863+
{
864+
// We use the same error code in both branches, because this is really the same
865+
// issue: we just special-case the message for type parameters to make it
866+
// clearer.
867+
match non_structural_match_ty.kind() {
868+
ty::Param(_) => {
869+
// Const parameters may not have type parameters as their types,
870+
// because we cannot be sure that the type parameter derives `PartialEq`
871+
// and `Eq` (just implementing them is not enough for `structural_match`).
872+
struct_span_err!(
873+
tcx.sess,
874+
hir_ty.span,
875+
E0741,
876+
"`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
877+
used as the type of a const parameter",
878+
)
879+
.span_label(
880+
hir_ty.span,
881+
format!("`{ty}` may not derive both `PartialEq` and `Eq`"),
882+
)
883+
.note(
884+
"it is not currently possible to use a type parameter as the type of a \
885+
const parameter",
886+
)
887+
.emit();
888+
}
889+
ty::Float(_) => {
890+
struct_span_err!(
891+
tcx.sess,
892+
hir_ty.span,
893+
E0741,
894+
"`{ty}` is forbidden as the type of a const generic parameter",
895+
)
896+
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
897+
.emit();
898+
}
899+
ty::FnPtr(_) => {
900+
struct_span_err!(
901+
tcx.sess,
902+
hir_ty.span,
903+
E0741,
904+
"using function pointers as const generic parameters is forbidden",
905+
)
906+
.emit();
907+
}
908+
ty::RawPtr(_) => {
909+
struct_span_err!(
910+
tcx.sess,
911+
hir_ty.span,
912+
E0741,
913+
"using raw pointers as const generic parameters is forbidden",
914+
)
915+
.emit();
916+
}
917+
_ => {
918+
let mut diag = struct_span_err!(
919+
tcx.sess,
920+
hir_ty.span,
921+
E0741,
922+
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
923+
the type of a const parameter",
924+
non_structural_match_ty,
925+
);
861926

862-
if tcx.features().adt_const_params {
863-
if let Some(non_structural_match_ty) =
864-
traits::search_for_adt_const_param_violation(param.span, tcx, ty)
865-
{
866-
// We use the same error code in both branches, because this is really the same
867-
// issue: we just special-case the message for type parameters to make it
868-
// clearer.
869-
match non_structural_match_ty.kind() {
870-
ty::Param(_) => {
871-
// Const parameters may not have type parameters as their types,
872-
// because we cannot be sure that the type parameter derives `PartialEq`
873-
// and `Eq` (just implementing them is not enough for `structural_match`).
874-
struct_span_err!(
875-
tcx.sess,
876-
hir_ty.span,
877-
E0741,
878-
"`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
879-
used as the type of a const parameter",
880-
)
881-
.span_label(
882-
hir_ty.span,
883-
format!("`{ty}` may not derive both `PartialEq` and `Eq`"),
884-
)
885-
.note(
886-
"it is not currently possible to use a type parameter as the type of a \
887-
const parameter",
888-
)
889-
.emit();
890-
}
891-
ty::Float(_) => {
892-
struct_span_err!(
893-
tcx.sess,
894-
hir_ty.span,
895-
E0741,
896-
"`{ty}` is forbidden as the type of a const generic parameter",
897-
)
898-
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
899-
.emit();
927+
if ty == non_structural_match_ty {
928+
diag.span_label(
929+
hir_ty.span,
930+
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
931+
);
932+
}
933+
934+
diag.emit();
935+
}
900936
}
901-
ty::FnPtr(_) => {
902-
struct_span_err!(
903-
tcx.sess,
904-
hir_ty.span,
905-
E0741,
906-
"using function pointers as const generic parameters is forbidden",
907-
)
908-
.emit();
937+
}
938+
} else {
939+
let err_ty_str;
940+
let mut is_ptr = true;
941+
942+
let err = match ty.kind() {
943+
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
944+
ty::FnPtr(_) => Some("function pointers"),
945+
ty::RawPtr(_) => Some("raw pointers"),
946+
_ => {
947+
is_ptr = false;
948+
err_ty_str = format!("`{ty}`");
949+
Some(err_ty_str.as_str())
909950
}
910-
ty::RawPtr(_) => {
911-
struct_span_err!(
912-
tcx.sess,
951+
};
952+
953+
if let Some(unsupported_type) = err {
954+
if is_ptr {
955+
tcx.sess.span_err(
913956
hir_ty.span,
914-
E0741,
915-
"using raw pointers as const generic parameters is forbidden",
916-
)
917-
.emit();
918-
}
919-
// Should have been normalized in
920-
// `traits::search_for_adt_const_param_violation`
921-
ty::Projection(_) => unreachable!(),
922-
_ => {
923-
let mut diag = struct_span_err!(
924-
tcx.sess,
957+
&format!(
958+
"using {unsupported_type} as const generic parameters is forbidden",
959+
),
960+
);
961+
} else {
962+
let mut err = tcx.sess.struct_span_err(
925963
hir_ty.span,
926-
E0741,
927-
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
928-
the type of a const parameter",
929-
non_structural_match_ty,
964+
&format!(
965+
"{unsupported_type} is forbidden as the type of a const generic parameter",
966+
),
967+
);
968+
err.note("the only supported types are integers, `bool` and `char`");
969+
if tcx.sess.is_nightly_build() {
970+
err.help(
971+
"more complex types are supported with `#![feature(adt_const_params)]`",
930972
);
931-
932-
if ty == non_structural_match_ty {
933-
diag.span_label(
934-
hir_ty.span,
935-
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
936-
);
937973
}
938-
939-
diag.emit();
974+
err.emit();
940975
}
941976
}
942977
}
943-
} else {
944-
let err_ty_str;
945-
let mut is_ptr = true;
946-
947-
let err = match ty.kind() {
948-
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
949-
ty::FnPtr(_) => Some("function pointers"),
950-
ty::RawPtr(_) => Some("raw pointers"),
951-
_ => {
952-
is_ptr = false;
953-
err_ty_str = format!("`{ty}`");
954-
Some(err_ty_str.as_str())
955-
}
956-
};
957-
958-
if let Some(unsupported_type) = err {
959-
if is_ptr {
960-
tcx.sess.span_err(
961-
hir_ty.span,
962-
&format!(
963-
"using {unsupported_type} as const generic parameters is forbidden",
964-
),
965-
);
966-
} else {
967-
let mut err = tcx.sess.struct_span_err(
968-
hir_ty.span,
969-
&format!(
970-
"{unsupported_type} is forbidden as the type of a const generic parameter",
971-
),
972-
);
973-
err.note("the only supported types are integers, `bool` and `char`");
974-
if tcx.sess.is_nightly_build() {
975-
err.help(
976-
"more complex types are supported with `#![feature(adt_const_params)]`",
977-
);
978-
}
979-
err.emit();
980-
}
981-
}
982-
}
978+
});
983979
}
984980
}
985981
}

compiler/rustc_middle/src/ty/consts.rs

+5
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ impl<'tcx> Const<'tcx> {
7474

7575
let ty = tcx.type_of(def.def_id_for_type_of());
7676

77+
let param_env = tcx.param_env(def.did);
78+
// We check that the `ty` is well formed in `wfcheck::check_param_wf` so
79+
// this should always succeed.
80+
let ty = tcx.normalize_erasing_regions(param_env, ty);
81+
7782
match Self::try_eval_lit_or_param(tcx, ty, expr) {
7883
Some(v) => v,
7984
None => tcx.mk_const(
+23-43
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,36 @@
11
use rustc_ast as ast;
22
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
3-
use rustc_middle::ty::{self, ParamEnv, ScalarInt, Ty, TyCtxt};
3+
use rustc_middle::ty::visit::TypeVisitable;
4+
use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
45
use rustc_span::DUMMY_SP;
56

6-
fn trunc<'tcx>(
7+
pub(crate) fn lit_to_const<'tcx>(
78
tcx: TyCtxt<'tcx>,
8-
ty: Ty<'tcx>,
9-
lit: &ast::LitKind,
10-
n: u128,
11-
) -> Result<ScalarInt, LitToConstError> {
12-
let param_ty = ParamEnv::reveal_all().and(ty);
13-
let width =
14-
tcx.layout_of(param_ty)
9+
lit_input: LitToConstInput<'tcx>,
10+
) -> Result<ty::Const<'tcx>, LitToConstError> {
11+
let LitToConstInput { lit, ty, neg } = lit_input;
12+
assert!(!TypeVisitable::has_projections(&ty));
13+
14+
let trunc = |n| {
15+
let param_ty = ParamEnv::reveal_all().and(ty);
16+
let width = tcx
17+
.layout_of(param_ty)
1518
.map_err(|_| {
1619
LitToConstError::Reported(tcx.sess.delay_span_bug(
1720
DUMMY_SP,
18-
format!("couldn't compute width of literal: {:?}", lit),
21+
format!("couldn't compute width of literal: {:?}", lit_input.lit),
1922
))
2023
})?
2124
.size;
22-
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
23-
let result = width.truncate(n);
24-
trace!("trunc result: {}", result);
25+
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
26+
let result = width.truncate(n);
27+
trace!("trunc result: {}", result);
2528

26-
Ok(ScalarInt::try_from_uint(result, width)
27-
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
28-
}
29+
Ok(ScalarInt::try_from_uint(result, width)
30+
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
31+
};
2932

30-
fn get_valtree<'tcx>(
31-
tcx: TyCtxt<'tcx>,
32-
ty: Ty<'tcx>,
33-
neg: bool,
34-
lit: &ast::LitKind,
35-
) -> Result<ty::ValTree<'tcx>, LitToConstError> {
36-
Ok(match (lit, &ty.kind()) {
33+
let valtree = match (lit, &ty.kind()) {
3734
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
3835
let str_bytes = s.as_str().as_bytes();
3936
ty::ValTree::from_raw_bytes(tcx, str_bytes)
@@ -52,12 +49,8 @@ fn get_valtree<'tcx>(
5249
ty::ValTree::from_scalar_int((*n).into())
5350
}
5451
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
55-
let scalar_int = trunc(
56-
tcx,
57-
ty,
58-
lit,
59-
if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n },
60-
)?;
52+
let scalar_int =
53+
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
6154
ty::ValTree::from_scalar_int(scalar_int)
6255
}
6356
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
@@ -67,21 +60,8 @@ fn get_valtree<'tcx>(
6760
tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
6861
));
6962
}
70-
(_, ty::Projection(ty::ProjectionTy { substs, item_def_id })) => {
71-
let binder_ty = tcx.bound_type_of(*item_def_id);
72-
let ty = binder_ty.subst(tcx, substs);
73-
get_valtree(tcx, ty, neg, lit)?
74-
}
7563
_ => return Err(LitToConstError::TypeError),
76-
})
77-
}
78-
79-
pub(crate) fn lit_to_const<'tcx>(
80-
tcx: TyCtxt<'tcx>,
81-
lit_input: LitToConstInput<'tcx>,
82-
) -> Result<ty::Const<'tcx>, LitToConstError> {
83-
let LitToConstInput { lit, ty, neg } = lit_input;
64+
};
8465

85-
let valtree = get_valtree(tcx, ty, neg, lit)?;
8666
Ok(ty::Const::from_value(tcx, valtree, ty))
8767
}

0 commit comments

Comments
 (0)