11// Not in interpret to make sure we do not use private implementation details
22
3- use std:: convert:: TryFrom ;
4-
53use rustc_hir:: Mutability ;
64use rustc_middle:: mir;
75use rustc_middle:: mir:: interpret:: { EvalToValTreeResult , GlobalId } ;
86use rustc_middle:: ty:: { self , TyCtxt } ;
97use rustc_span:: { source_map:: DUMMY_SP , symbol:: Symbol } ;
8+ use rustc_target:: abi:: VariantIdx ;
109
1110use crate :: interpret:: {
1211 intern_const_alloc_recursive, ConstValue , InternKind , InterpCx , InterpResult , MemPlaceMeta ,
@@ -40,7 +39,7 @@ pub(crate) fn const_caller_location(
4039}
4140
4241// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
43- const VALTREE_MAX_NODES : usize = 1000 ;
42+ const VALTREE_MAX_NODES : usize = 100000 ;
4443
4544pub ( crate ) enum ValTreeCreationError {
4645 NodesOverflow ,
@@ -56,6 +55,8 @@ pub(crate) fn eval_to_valtree<'tcx>(
5655 cid : GlobalId < ' tcx > ,
5756) -> EvalToValTreeResult < ' tcx > {
5857 let const_alloc = tcx. eval_to_allocation_raw ( param_env. and ( cid) ) ?;
58+
59+ // FIXME Need to provide a span to `eval_to_valtree`
5960 let ecx = mk_eval_cx (
6061 tcx, DUMMY_SP , param_env,
6162 // It is absolutely crucial for soundness that
@@ -90,40 +91,81 @@ pub(crate) fn eval_to_valtree<'tcx>(
9091 }
9192}
9293
93- /// This function should never fail for validated constants. However, it is also invoked from the
94- /// pretty printer which might attempt to format invalid constants and in that case it might fail .
94+ /// Tries to destructure constants of type Array or Adt into the constants
95+ /// of its fields .
9596pub ( crate ) fn try_destructure_const < ' tcx > (
9697 tcx : TyCtxt < ' tcx > ,
97- param_env : ty:: ParamEnv < ' tcx > ,
98- val : ty:: Const < ' tcx > ,
99- ) -> InterpResult < ' tcx , mir:: DestructuredConst < ' tcx > > {
100- trace ! ( "destructure_const: {:?}" , val) ;
101- let ecx = mk_eval_cx ( tcx, DUMMY_SP , param_env, false ) ;
102- let op = ecx. const_to_op ( val, None ) ?;
103- // We go to `usize` as we cannot allocate anything bigger anyway.
104- let ( field_count, variant, down) = match val. ty ( ) . kind ( ) {
105- ty:: Array ( _, len) => ( usize:: try_from ( len. eval_usize ( tcx, param_env) ) . unwrap ( ) , None , op) ,
106- // Checks if we have any variants, to avoid downcasting to a non-existing variant (when
107- // there are no variants `read_discriminant` successfully returns a non-existing variant
108- // index).
109- ty:: Adt ( def, _) if def. variants ( ) . is_empty ( ) => throw_ub ! ( Unreachable ) ,
110- ty:: Adt ( def, _) => {
111- let variant = ecx. read_discriminant ( & op) ?. 1 ;
112- let down = ecx. operand_downcast ( & op, variant) ?;
113- ( def. variant ( variant) . fields . len ( ) , Some ( variant) , down)
114- }
115- ty:: Tuple ( substs) => ( substs. len ( ) , None , op) ,
116- _ => bug ! ( "cannot destructure constant {:?}" , val) ,
117- } ;
118- let fields = ( 0 ..field_count)
119- . map ( |i| {
120- let field_op = ecx. operand_field ( & down, i) ?;
121- let val = op_to_const ( & ecx, & field_op) ;
122- Ok ( ty:: Const :: from_value ( tcx, val, field_op. layout . ty ) )
123- } )
124- . collect :: < InterpResult < ' tcx , Vec < _ > > > ( ) ?;
125- let fields = tcx. arena . alloc_from_iter ( fields) ;
126- Ok ( mir:: DestructuredConst { variant, fields } )
98+ const_ : ty:: Const < ' tcx > ,
99+ ) -> Option < ty:: DestructuredConst < ' tcx > > {
100+ if let ty:: ConstKind :: Value ( valtree) = const_. kind ( ) {
101+ let branches = match valtree {
102+ ty:: ValTree :: Branch ( b) => b,
103+ _ => return None ,
104+ } ;
105+
106+ let ( fields, variant) = match const_. ty ( ) . kind ( ) {
107+ ty:: Array ( inner_ty, _) | ty:: Slice ( inner_ty) => {
108+ // construct the consts for the elements of the array/slice
109+ let field_consts = branches
110+ . iter ( )
111+ . map ( |b| {
112+ tcx. mk_const ( ty:: ConstS { kind : ty:: ConstKind :: Value ( * b) , ty : * inner_ty } )
113+ } )
114+ . collect :: < Vec < _ > > ( ) ;
115+ debug ! ( ?field_consts) ;
116+
117+ ( field_consts, None )
118+ }
119+ ty:: Adt ( def, _) if def. variants ( ) . is_empty ( ) => bug ! ( "unreachable" ) ,
120+ ty:: Adt ( def, substs) => {
121+ let variant_idx = if def. is_enum ( ) {
122+ VariantIdx :: from_u32 ( branches[ 0 ] . unwrap_leaf ( ) . try_to_u32 ( ) . ok ( ) ?)
123+ } else {
124+ VariantIdx :: from_u32 ( 0 )
125+ } ;
126+ let fields = & def. variant ( variant_idx) . fields ;
127+ let mut field_consts = Vec :: with_capacity ( fields. len ( ) ) ;
128+
129+ // Note: First element inValTree corresponds to variant of enum
130+ let mut valtree_idx = if def. is_enum ( ) { 1 } else { 0 } ;
131+ for field in fields {
132+ let field_ty = field. ty ( tcx, substs) ;
133+ let field_valtree = branches[ valtree_idx] ; // first element of branches is variant
134+ let field_const = tcx. mk_const ( ty:: ConstS {
135+ kind : ty:: ConstKind :: Value ( field_valtree) ,
136+ ty : field_ty,
137+ } ) ;
138+ field_consts. push ( field_const) ;
139+ valtree_idx += 1 ;
140+ }
141+ debug ! ( ?field_consts) ;
142+
143+ ( field_consts, Some ( variant_idx) )
144+ }
145+ ty:: Tuple ( elem_tys) => {
146+ let fields = elem_tys
147+ . iter ( )
148+ . enumerate ( )
149+ . map ( |( i, elem_ty) | {
150+ let elem_valtree = branches[ i] ;
151+ tcx. mk_const ( ty:: ConstS {
152+ kind : ty:: ConstKind :: Value ( elem_valtree) ,
153+ ty : elem_ty,
154+ } )
155+ } )
156+ . collect :: < Vec < _ > > ( ) ;
157+
158+ ( fields, None )
159+ }
160+ _ => bug ! ( "cannot destructure constant {:?}" , const_) ,
161+ } ;
162+
163+ let fields = tcx. arena . alloc_from_iter ( fields. into_iter ( ) ) ;
164+
165+ Some ( ty:: DestructuredConst { variant, fields } )
166+ } else {
167+ None
168+ }
127169}
128170
129171#[ instrument( skip( tcx) , level = "debug" ) ]
@@ -143,8 +185,8 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
143185 throw_ub ! ( Unreachable )
144186 }
145187 ty:: Adt ( def, _) => {
146- let variant = ecx. read_discriminant ( & op) . unwrap ( ) . 1 ;
147- let down = ecx. operand_downcast ( & op, variant) . unwrap ( ) ;
188+ let variant = ecx. read_discriminant ( & op) ? . 1 ;
189+ let down = ecx. operand_downcast ( & op, variant) ? ;
148190 ( def. variants ( ) [ variant] . fields . len ( ) , Some ( variant) , down)
149191 }
150192 ty:: Tuple ( substs) => ( substs. len ( ) , None , op) ,
@@ -163,43 +205,6 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
163205 Ok ( mir:: DestructuredMirConstant { variant, fields } )
164206}
165207
166- #[ instrument( skip( tcx) , level = "debug" ) ]
167- pub ( crate ) fn deref_const < ' tcx > (
168- tcx : TyCtxt < ' tcx > ,
169- param_env : ty:: ParamEnv < ' tcx > ,
170- val : ty:: Const < ' tcx > ,
171- ) -> ty:: Const < ' tcx > {
172- trace ! ( "deref_const: {:?}" , val) ;
173- let ecx = mk_eval_cx ( tcx, DUMMY_SP , param_env, false ) ;
174- let op = ecx. const_to_op ( val, None ) . unwrap ( ) ;
175- let mplace = ecx. deref_operand ( & op) . unwrap ( ) ;
176- if let Some ( alloc_id) = mplace. ptr . provenance {
177- assert_eq ! (
178- tcx. get_global_alloc( alloc_id) . unwrap( ) . unwrap_memory( ) . inner( ) . mutability,
179- Mutability :: Not ,
180- "deref_const cannot be used with mutable allocations as \
181- that could allow pattern matching to observe mutable statics",
182- ) ;
183- }
184-
185- let ty = match mplace. meta {
186- MemPlaceMeta :: None => mplace. layout . ty ,
187- MemPlaceMeta :: Poison => bug ! ( "poison metadata in `deref_const`: {:#?}" , mplace) ,
188- // In case of unsized types, figure out the real type behind.
189- MemPlaceMeta :: Meta ( scalar) => match mplace. layout . ty . kind ( ) {
190- ty:: Str => bug ! ( "there's no sized equivalent of a `str`" ) ,
191- ty:: Slice ( elem_ty) => tcx. mk_array ( * elem_ty, scalar. to_machine_usize ( & tcx) . unwrap ( ) ) ,
192- _ => bug ! (
193- "type {} should not have metadata, but had {:?}" ,
194- mplace. layout. ty,
195- mplace. meta
196- ) ,
197- } ,
198- } ;
199-
200- tcx. mk_const ( ty:: ConstS { kind : ty:: ConstKind :: Value ( op_to_const ( & ecx, & mplace. into ( ) ) ) , ty } )
201- }
202-
203208#[ instrument( skip( tcx) , level = "debug" ) ]
204209pub ( crate ) fn deref_mir_constant < ' tcx > (
205210 tcx : TyCtxt < ' tcx > ,
@@ -213,14 +218,14 @@ pub(crate) fn deref_mir_constant<'tcx>(
213218 assert_eq ! (
214219 tcx. get_global_alloc( alloc_id) . unwrap( ) . unwrap_memory( ) . 0.0 . mutability,
215220 Mutability :: Not ,
216- "deref_const cannot be used with mutable allocations as \
221+ "deref_mir_constant cannot be used with mutable allocations as \
217222 that could allow pattern matching to observe mutable statics",
218223 ) ;
219224 }
220225
221226 let ty = match mplace. meta {
222227 MemPlaceMeta :: None => mplace. layout . ty ,
223- MemPlaceMeta :: Poison => bug ! ( "poison metadata in `deref_const `: {:#?}" , mplace) ,
228+ MemPlaceMeta :: Poison => bug ! ( "poison metadata in `deref_mir_constant `: {:#?}" , mplace) ,
224229 // In case of unsized types, figure out the real type behind.
225230 MemPlaceMeta :: Meta ( scalar) => match mplace. layout . ty . kind ( ) {
226231 ty:: Str => bug ! ( "there's no sized equivalent of a `str`" ) ,
0 commit comments