Skip to content

Commit e08830e

Browse files
committed
mGCA: Validate const literal against expected type
1 parent a1db344 commit e08830e

5 files changed

Lines changed: 150 additions & 2 deletions

File tree

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub mod generics;
2121

2222
use std::slice;
2323

24-
use rustc_ast::LitKind;
24+
use rustc_ast::{LitFloatType, LitIntType, LitKind};
2525
use rustc_data_structures::assert_matches;
2626
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
2727
use rustc_errors::codes::*;
@@ -31,7 +31,7 @@ use rustc_errors::{
3131
use rustc_hir::attrs::AttributeKind;
3232
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
3333
use rustc_hir::def_id::{DefId, LocalDefId};
34-
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId, find_attr};
34+
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId, LangItem, find_attr};
3535
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3636
use rustc_infer::traits::DynCompatibilityViolation;
3737
use rustc_macros::{TypeFoldable, TypeVisitable};
@@ -2807,10 +2807,70 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
28072807
#[instrument(skip(self), level = "debug")]
28082808
fn lower_const_arg_literal(&self, kind: &LitKind, ty: Ty<'tcx>, span: Span) -> Const<'tcx> {
28092809
let tcx = self.tcx();
2810+
if let LitKind::Err(guar) = *kind {
2811+
return ty::Const::new_error(tcx, guar);
2812+
}
2813+
if !self.const_lit_matches_ty(kind, ty, false) {
2814+
let found = self.const_lit_description(kind);
2815+
let e = tcx.dcx().span_err(span, format!("expected `{}`, found `{found}`", ty));
2816+
return ty::Const::new_error(tcx, e);
2817+
}
28102818
let input = LitToConstInput { lit: *kind, ty, neg: false };
28112819
tcx.at(span).lit_to_const(input)
28122820
}
28132821

2822+
fn const_lit_matches_ty(&self, kind: &LitKind, ty: Ty<'tcx>, neg: bool) -> bool {
2823+
let tcx = self.tcx();
2824+
match (*kind, ty.kind()) {
2825+
(LitKind::Str(..), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => true,
2826+
(LitKind::Str(..), ty::Str) if tcx.features().deref_patterns() => true,
2827+
(LitKind::ByteStr(..), ty::Ref(_, inner_ty, _))
2828+
if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind()
2829+
&& matches!(ty.kind(), ty::Uint(ty::UintTy::U8)) =>
2830+
{
2831+
true
2832+
}
2833+
(LitKind::ByteStr(..), ty::Slice(inner_ty) | ty::Array(inner_ty, _))
2834+
if tcx.features().deref_patterns()
2835+
&& matches!(inner_ty.kind(), ty::Uint(ty::UintTy::U8)) =>
2836+
{
2837+
true
2838+
}
2839+
(LitKind::Byte(..), ty::Uint(ty::UintTy::U8)) => true,
2840+
(LitKind::CStr(..), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => {
2841+
true
2842+
}
2843+
(LitKind::Int(..), ty::Uint(_)) if !neg => true,
2844+
(LitKind::Int(..), ty::Int(_)) => true,
2845+
(LitKind::Bool(..), ty::Bool) => true,
2846+
(LitKind::Float(..), ty::Float(_)) => true,
2847+
(LitKind::Char(..), ty::Char) => true,
2848+
(LitKind::Err(..), _) => true,
2849+
_ => false,
2850+
}
2851+
}
2852+
2853+
fn const_lit_description(&self, kind: &LitKind) -> &'static str {
2854+
match *kind {
2855+
LitKind::Str(..) => "&str",
2856+
LitKind::ByteStr(..) => "&[u8]",
2857+
LitKind::CStr(..) => "&CStr",
2858+
LitKind::Byte(..) => "u8",
2859+
LitKind::Int(_, suffix) => match suffix {
2860+
LitIntType::Signed(int_ty) => int_ty.name_str(),
2861+
LitIntType::Unsigned(uint_ty) => uint_ty.name_str(),
2862+
LitIntType::Unsuffixed => "{integer}",
2863+
},
2864+
LitKind::Float(_, suffix) => match suffix {
2865+
LitFloatType::Suffixed(float_ty) => float_ty.name_str(),
2866+
LitFloatType::Unsuffixed => "{float}",
2867+
},
2868+
LitKind::Bool(..) => "bool",
2869+
LitKind::Char(..) => "char",
2870+
LitKind::Err(..) => "erroneous literal",
2871+
}
2872+
}
2873+
28142874
#[instrument(skip(self), level = "debug")]
28152875
fn try_lower_anon_const_lit(
28162876
&self,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/150983>
2+
#![expect(incomplete_features)]
3+
#![feature(
4+
generic_const_items,
5+
generic_const_parameter_types,
6+
min_generic_const_args,
7+
unsized_const_params
8+
)]
9+
use std::marker::ConstParamTy_;
10+
11+
struct Foo<T> {
12+
field: T,
13+
}
14+
15+
#[type_const]
16+
const WRAP<T : ConstParamTy_> : T = {
17+
Foo::<T>{field : 1} //~ ERROR: expected `T`, found `{integer}`
18+
};
19+
20+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected `T`, found `{integer}`
2+
--> $DIR/generic_const_type_mismatch.rs:17:22
3+
|
4+
LL | Foo::<T>{field : 1}
5+
| ^
6+
7+
error: aborting due to 1 previous error
8+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/151625>
2+
#![expect(incomplete_features)]
3+
#![feature(
4+
adt_const_params,
5+
min_generic_const_args,
6+
unsized_const_params
7+
)]
8+
fn foo<const X: (bool, i32)>() {}
9+
fn bar<const Y: ([u8; 2], i32)>() {}
10+
fn qux<const Z: (char, i32)>() {}
11+
12+
fn main() {
13+
foo::<{ (1, true) }>();
14+
//~^ ERROR: expected `bool`, found `{integer}`
15+
//~| ERROR: expected `i32`, found `bool`
16+
bar::<{ (1_u32, [1, 2]) }>();
17+
//~^ ERROR: expected `[u8; 2]`, found `u32`
18+
//~| ERROR: expected `i32`, found const array
19+
qux::<{ (1i32, 'a') }>();
20+
//~^ ERROR: expected `char`, found `i32`
21+
//~| ERROR: expected `i32`, found `char`
22+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error: expected `bool`, found `{integer}`
2+
--> $DIR/tuple_expr_type_mismatch.rs:13:14
3+
|
4+
LL | foo::<{ (1, true) }>();
5+
| ^
6+
7+
error: expected `i32`, found `bool`
8+
--> $DIR/tuple_expr_type_mismatch.rs:13:17
9+
|
10+
LL | foo::<{ (1, true) }>();
11+
| ^^^^
12+
13+
error: expected `[u8; 2]`, found `u32`
14+
--> $DIR/tuple_expr_type_mismatch.rs:16:14
15+
|
16+
LL | bar::<{ (1_u32, [1, 2]) }>();
17+
| ^^^^^
18+
19+
error: expected `i32`, found const array
20+
--> $DIR/tuple_expr_type_mismatch.rs:16:21
21+
|
22+
LL | bar::<{ (1_u32, [1, 2]) }>();
23+
| ^^^^^^
24+
25+
error: expected `char`, found `i32`
26+
--> $DIR/tuple_expr_type_mismatch.rs:19:14
27+
|
28+
LL | qux::<{ (1i32, 'a') }>();
29+
| ^^^^
30+
31+
error: expected `i32`, found `char`
32+
--> $DIR/tuple_expr_type_mismatch.rs:19:20
33+
|
34+
LL | qux::<{ (1i32, 'a') }>();
35+
| ^^^
36+
37+
error: aborting due to 6 previous errors
38+

0 commit comments

Comments
 (0)