1
1
//! See docs in build/expr/mod.rs
2
2
3
3
use crate :: build:: Builder ;
4
+ use crate :: thir:: constant:: parse_float;
5
+ use rustc_ast as ast;
4
6
use rustc_hir:: def_id:: DefId ;
7
+ use rustc_middle:: mir:: interpret:: Allocation ;
5
8
use rustc_middle:: mir:: interpret:: { ConstValue , LitToConstError , LitToConstInput , Scalar } ;
6
9
use rustc_middle:: mir:: * ;
7
10
use rustc_middle:: thir:: * ;
8
11
use rustc_middle:: ty:: subst:: SubstsRef ;
9
12
use rustc_middle:: ty:: { self , CanonicalUserTypeAnnotation , Ty , TyCtxt } ;
13
+ use rustc_target:: abi:: Size ;
10
14
11
15
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
12
16
/// Compile `expr`, yielding a compile-time constant. Assumes that
@@ -27,7 +31,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
27
31
}
28
32
ExprKind :: Literal { lit, neg } => {
29
33
let literal =
30
- match tcx . lit_to_mir_constant ( LitToConstInput { lit : & lit. node , ty, neg } ) {
34
+ match lit_to_mir_constant ( tcx , LitToConstInput { lit : & lit. node , ty, neg } ) {
31
35
Ok ( c) => c,
32
36
Err ( LitToConstError :: Reported ) => ConstantKind :: Ty ( tcx. const_error ( ty) ) ,
33
37
Err ( LitToConstError :: TypeError ) => {
@@ -84,3 +88,54 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
84
88
}
85
89
}
86
90
}
91
+
92
+ #[ instrument( skip( tcx, lit_input) ) ]
93
+ fn lit_to_mir_constant < ' tcx > (
94
+ tcx : TyCtxt < ' tcx > ,
95
+ lit_input : LitToConstInput < ' tcx > ,
96
+ ) -> Result < ConstantKind < ' tcx > , LitToConstError > {
97
+ let LitToConstInput { lit, ty, neg } = lit_input;
98
+ let trunc = |n| {
99
+ let param_ty = ty:: ParamEnv :: reveal_all ( ) . and ( ty) ;
100
+ let width = tcx. layout_of ( param_ty) . map_err ( |_| LitToConstError :: Reported ) ?. size ;
101
+ trace ! ( "trunc {} with size {} and shift {}" , n, width. bits( ) , 128 - width. bits( ) ) ;
102
+ let result = width. truncate ( n) ;
103
+ trace ! ( "trunc result: {}" , result) ;
104
+ Ok ( ConstValue :: Scalar ( Scalar :: from_uint ( result, width) ) )
105
+ } ;
106
+
107
+ let value = match ( lit, & ty. kind ( ) ) {
108
+ ( ast:: LitKind :: Str ( s, _) , ty:: Ref ( _, inner_ty, _) ) if inner_ty. is_str ( ) => {
109
+ let s = s. as_str ( ) ;
110
+ let allocation = Allocation :: from_bytes_byte_aligned_immutable ( s. as_bytes ( ) ) ;
111
+ let allocation = tcx. intern_const_alloc ( allocation) ;
112
+ ConstValue :: Slice { data : allocation, start : 0 , end : s. len ( ) }
113
+ }
114
+ ( ast:: LitKind :: ByteStr ( data) , ty:: Ref ( _, inner_ty, _) )
115
+ if matches ! ( inner_ty. kind( ) , ty:: Slice ( _) ) =>
116
+ {
117
+ let allocation = Allocation :: from_bytes_byte_aligned_immutable ( data as & [ u8 ] ) ;
118
+ let allocation = tcx. intern_const_alloc ( allocation) ;
119
+ ConstValue :: Slice { data : allocation, start : 0 , end : data. len ( ) }
120
+ }
121
+ ( ast:: LitKind :: ByteStr ( data) , ty:: Ref ( _, inner_ty, _) ) if inner_ty. is_array ( ) => {
122
+ let id = tcx. allocate_bytes ( data) ;
123
+ ConstValue :: Scalar ( Scalar :: from_pointer ( id. into ( ) , & tcx) )
124
+ }
125
+ ( ast:: LitKind :: Byte ( n) , ty:: Uint ( ty:: UintTy :: U8 ) ) => {
126
+ ConstValue :: Scalar ( Scalar :: from_uint ( * n, Size :: from_bytes ( 1 ) ) )
127
+ }
128
+ ( ast:: LitKind :: Int ( n, _) , ty:: Uint ( _) ) | ( ast:: LitKind :: Int ( n, _) , ty:: Int ( _) ) => {
129
+ trunc ( if neg { ( * n as i128 ) . overflowing_neg ( ) . 0 as u128 } else { * n } ) ?
130
+ }
131
+ ( ast:: LitKind :: Float ( n, _) , ty:: Float ( fty) ) => {
132
+ parse_float ( * n, * fty, neg) . ok_or ( LitToConstError :: Reported ) ?
133
+ }
134
+ ( ast:: LitKind :: Bool ( b) , ty:: Bool ) => ConstValue :: Scalar ( Scalar :: from_bool ( * b) ) ,
135
+ ( ast:: LitKind :: Char ( c) , ty:: Char ) => ConstValue :: Scalar ( Scalar :: from_char ( * c) ) ,
136
+ ( ast:: LitKind :: Err ( _) , _) => return Err ( LitToConstError :: Reported ) ,
137
+ _ => return Err ( LitToConstError :: TypeError ) ,
138
+ } ;
139
+
140
+ Ok ( ConstantKind :: Val ( value, ty) )
141
+ }
0 commit comments