Skip to content

Commit 4c05757

Browse files
Split out bad lit_to_const_for_patterns
1 parent 7b4b1b0 commit 4c05757

File tree

9 files changed

+97
-27
lines changed

9 files changed

+97
-27
lines changed

compiler/rustc_middle/src/query/erase.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
182182
type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
183183
}
184184

185+
impl EraseType for Option<ty::Const<'_>> {
186+
type Result = [u8; size_of::<Option<ty::Const<'static>>>()];
187+
}
188+
185189
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
186190
type Result = [u8; size_of::<(&'static (), &'static ())>()];
187191
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,13 +1111,21 @@ rustc_queries! {
11111111
desc { "getting a &core::panic::Location referring to a span" }
11121112
}
11131113

1114-
// FIXME get rid of this with valtrees
11151114
query lit_to_const(
11161115
key: LitToConstInput<'tcx>
1117-
) -> Result<ty::Const<'tcx>, LitToConstError> {
1116+
) -> Option<ty::Const<'tcx>> {
11181117
desc { "converting literal to const" }
11191118
}
11201119

1120+
// FIXME: We could get rid of this if we got rid of float patterns, for
1121+
// example, but we would also need to make sure that other things like
1122+
// const type mismatches are handled elsewhere.
1123+
query lit_to_const_for_patterns(
1124+
key: LitToConstInput<'tcx>
1125+
) -> Result<ty::Const<'tcx>, LitToConstError> {
1126+
desc { "converting literal to pattern const" }
1127+
}
1128+
11211129
query check_match(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> {
11221130
desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
11231131
cache_on_disk_if { true }

compiler/rustc_middle/src/ty/consts.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,10 @@ impl<'tcx> Const<'tcx> {
194194
};
195195

196196
if let Some(lit_input) = lit_input {
197-
// If an error occurred, ignore that it's a literal and leave reporting the error up to
198-
// mir.
199-
match tcx.at(expr.span).lit_to_const(lit_input) {
200-
Ok(c) => return Some(c),
201-
Err(e) => {
202-
tcx.sess.delay_span_bug(
203-
expr.span,
204-
format!("Const::from_anon_const: couldn't lit_to_const {e:?}"),
205-
);
206-
}
207-
}
197+
// If we failed to validate the type of the lit (which we sometimes
198+
// need to actually build the valtree), then return `None`, which
199+
// will make it fall back to using an unevaluated const.
200+
return tcx.at(expr.span).lit_to_const(lit_input);
208201
}
209202

210203
match expr.kind {

compiler/rustc_mir_build/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fluent_messages! { "../messages.ftl" }
3232
pub fn provide(providers: &mut Providers) {
3333
providers.check_match = thir::pattern::check_match;
3434
providers.lit_to_const = thir::constant::lit_to_const;
35+
providers.lit_to_const_for_patterns = thir::constant::lit_to_const_for_patterns;
3536
providers.mir_built = build::mir_built;
3637
providers.closure_saved_names_of_captured_variables =
3738
build::closure_saved_names_of_captured_variables;

compiler/rustc_mir_build/src/thir/constant.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,66 @@ use crate::build::parse_float_into_scalar;
88
pub(crate) fn lit_to_const<'tcx>(
99
tcx: TyCtxt<'tcx>,
1010
lit_input: LitToConstInput<'tcx>,
11+
) -> Option<ty::Const<'tcx>> {
12+
let LitToConstInput { lit, ty, neg } = lit_input;
13+
14+
let valtree = match (lit, &ty.kind()) {
15+
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
16+
let str_bytes = s.as_str().as_bytes();
17+
ty::ValTree::from_raw_bytes(tcx, str_bytes)
18+
}
19+
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
20+
if matches!(inner_ty.kind(), ty::Slice(_)) =>
21+
{
22+
let bytes = data as &[u8];
23+
ty::ValTree::from_raw_bytes(tcx, bytes)
24+
}
25+
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
26+
let bytes = data as &[u8];
27+
ty::ValTree::from_raw_bytes(tcx, bytes)
28+
}
29+
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
30+
ty::ValTree::from_scalar_int((*n).into())
31+
}
32+
(ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
33+
{
34+
let bytes = data as &[u8];
35+
ty::ValTree::from_raw_bytes(tcx, bytes)
36+
}
37+
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
38+
let n = if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n };
39+
let param_ty = ParamEnv::reveal_all().and(ty);
40+
let width = tcx
41+
.layout_of(param_ty)
42+
.unwrap_or_else(|_| bug!("should always be able to compute the layout of a scalar"))
43+
.size;
44+
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
45+
let result = width.truncate(n);
46+
trace!("trunc result: {}", result);
47+
48+
let scalar_int = ScalarInt::try_from_uint(result, width)
49+
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result));
50+
51+
ty::ValTree::from_scalar_int(scalar_int)
52+
}
53+
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
54+
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
55+
// If there's a type mismatch, it may be a legitimate type mismatch, or
56+
// it might be an unnormalized type. Return `None`, which falls back
57+
// to an unevaluated const, and the error will be caught (or we will see
58+
// that it's ok) elsewhere.
59+
_ => return None,
60+
};
61+
62+
Some(ty::Const::new_value(tcx, valtree, ty))
63+
}
64+
65+
/// The old "lit_to_const", which assumes that the type passed in `lit_input`
66+
/// is normalized, and will error out if that is not true. This should only
67+
/// be used in pattern building code (and ideally we'd get rid of this altogether).
68+
pub(crate) fn lit_to_const_for_patterns<'tcx>(
69+
tcx: TyCtxt<'tcx>,
70+
lit_input: LitToConstInput<'tcx>,
1171
) -> Result<ty::Const<'tcx>, LitToConstError> {
1272
let LitToConstInput { lit, ty, neg } = lit_input;
1373

compiler/rustc_mir_build/src/thir/pattern/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
607607
_ => None,
608608
};
609609
if let Some(lit_input) = lit_input {
610-
match tcx.at(expr.span).lit_to_const(lit_input) {
610+
match tcx.at(expr.span).lit_to_const_for_patterns(lit_input) {
611611
Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind,
612612
// If an error occurred, ignore that it's a literal
613613
// and leave reporting the error up to const eval of
@@ -676,7 +676,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
676676

677677
let lit_input =
678678
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
679-
match self.tcx.at(expr.span).lit_to_const(lit_input) {
679+
match self.tcx.at(expr.span).lit_to_const_for_patterns(lit_input) {
680680
Ok(constant) => {
681681
self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
682682
}

compiler/rustc_ty_utils/src/consts.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,11 @@ fn recurse_build<'tcx>(
117117
}
118118
&ExprKind::Literal { lit, neg } => {
119119
let sp = node.span;
120-
match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) {
120+
match tcx.at(sp).lit_to_const_for_patterns(LitToConstInput {
121+
lit: &lit.node,
122+
ty: node.ty,
123+
neg,
124+
}) {
121125
Ok(c) => c,
122126
Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar, node.ty),
123127
Err(LitToConstError::TypeError) => {

tests/ui/const-generics/projection-as-arg-const.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
// This is currently not possible to use projections as const generics.
2-
// More information about this available here:
3-
// https://github.com/rust-lang/rust/pull/104443#discussion_r1029375633
1+
// build-pass
2+
3+
#![feature(adt_const_params)]
4+
//~^ WARN the feature `adt_const_params` is incomplete
45

56
pub trait Identity {
67
type Identity;
@@ -11,7 +12,6 @@ impl<T> Identity for T {
1112
}
1213

1314
pub fn foo<const X: <i32 as Identity>::Identity>() {
14-
//~^ ERROR
1515
assert!(X == 12);
1616
}
1717

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
error: `<i32 as Identity>::Identity` is forbidden as the type of a const generic parameter
2-
--> $DIR/projection-as-arg-const.rs:13:21
1+
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/projection-as-arg-const.rs:3:12
33
|
4-
LL | pub fn foo<const X: <i32 as Identity>::Identity>() {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | #![feature(adt_const_params)]
5+
| ^^^^^^^^^^^^^^^^
66
|
7-
= note: the only supported types are integers, `bool` and `char`
8-
= help: more complex types are supported with `#![feature(adt_const_params)]`
7+
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
99

10-
error: aborting due to previous error
10+
warning: 1 warning emitted
1111

0 commit comments

Comments
 (0)