11//! See docs in build/expr/mod.rs
22
33use crate :: build:: Builder ;
4+ use crate :: thir:: constant:: parse_float;
5+ use rustc_ast as ast;
46use rustc_hir:: def_id:: DefId ;
7+ use rustc_middle:: mir:: interpret:: Allocation ;
58use rustc_middle:: mir:: interpret:: { ConstValue , LitToConstError , LitToConstInput , Scalar } ;
69use rustc_middle:: mir:: * ;
710use rustc_middle:: thir:: * ;
811use rustc_middle:: ty:: subst:: SubstsRef ;
912use rustc_middle:: ty:: { self , CanonicalUserTypeAnnotation , Ty , TyCtxt } ;
13+ use rustc_target:: abi:: Size ;
1014
1115impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1216 /// Compile `expr`, yielding a compile-time constant. Assumes that
@@ -27,7 +31,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2731 }
2832 ExprKind :: Literal { lit, neg } => {
2933 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 } ) {
3135 Ok ( c) => c,
3236 Err ( LitToConstError :: Reported ) => ConstantKind :: Ty ( tcx. const_error ( ty) ) ,
3337 Err ( LitToConstError :: TypeError ) => {
@@ -84,3 +88,54 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
8488 }
8589 }
8690}
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