@@ -6,9 +6,10 @@ use rustc_hir::Mutability;
6
6
use rustc_middle:: ty:: { self , TyCtxt } ;
7
7
use rustc_middle:: {
8
8
mir:: { self , interpret:: ConstAlloc } ,
9
- ty:: ScalarInt ,
9
+ ty:: { ScalarInt , Ty } ,
10
10
} ;
11
11
use rustc_span:: { source_map:: DUMMY_SP , symbol:: Symbol } ;
12
+ use rustc_target:: abi:: VariantIdx ;
12
13
13
14
use crate :: interpret:: {
14
15
intern_const_alloc_recursive, ConstValue , InternKind , InterpCx , InterpResult , MPlaceTy ,
@@ -55,28 +56,43 @@ pub(crate) fn const_to_valtree<'tcx>(
55
56
const_to_valtree_inner ( & ecx, & place)
56
57
}
57
58
59
+ #[ instrument( skip( ecx) , level = "debug" ) ]
60
+ fn branches < ' tcx > (
61
+ ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
62
+ place : & MPlaceTy < ' tcx > ,
63
+ n : usize ,
64
+ variant : Option < VariantIdx > ,
65
+ ) -> Option < ty:: ValTree < ' tcx > > {
66
+ let place = match variant {
67
+ Some ( variant) => ecx. mplace_downcast ( & place, variant) . unwrap ( ) ,
68
+ None => * place,
69
+ } ;
70
+ let variant = variant. map ( |variant| Some ( ty:: ValTree :: Leaf ( ScalarInt :: from ( variant. as_u32 ( ) ) ) ) ) ;
71
+ debug ! ( ?place, ?variant) ;
72
+
73
+ let fields = ( 0 ..n) . map ( |i| {
74
+ let field = ecx. mplace_field ( & place, i) . unwrap ( ) ;
75
+ const_to_valtree_inner ( ecx, & field)
76
+ } ) ;
77
+ // For enums, we preped their variant index before the variant's fields so we can figure out
78
+ // the variant again when just seeing a valtree.
79
+ let branches = variant. into_iter ( ) . chain ( fields) ;
80
+ Some ( ty:: ValTree :: Branch ( ecx. tcx . arena . alloc_from_iter ( branches. collect :: < Option < Vec < _ > > > ( ) ?) ) )
81
+ }
82
+
83
+ #[ instrument( skip( ecx) , level = "debug" ) ]
58
84
fn const_to_valtree_inner < ' tcx > (
59
85
ecx : & CompileTimeEvalContext < ' tcx , ' tcx > ,
60
86
place : & MPlaceTy < ' tcx > ,
61
87
) -> Option < ty:: ValTree < ' tcx > > {
62
- let branches = |n, variant| {
63
- let place = match variant {
64
- Some ( variant) => ecx. mplace_downcast ( & place, variant) . unwrap ( ) ,
65
- None => * place,
66
- } ;
67
- let variant =
68
- variant. map ( |variant| Some ( ty:: ValTree :: Leaf ( ScalarInt :: from ( variant. as_u32 ( ) ) ) ) ) ;
69
- let fields = ( 0 ..n) . map ( |i| {
70
- let field = ecx. mplace_field ( & place, i) . unwrap ( ) ;
71
- const_to_valtree_inner ( ecx, & field)
72
- } ) ;
73
- // For enums, we preped their variant index before the variant's fields so we can figure out
74
- // the variant again when just seeing a valtree.
75
- let branches = variant. into_iter ( ) . chain ( fields) ;
76
- Some ( ty:: ValTree :: Branch (
77
- ecx. tcx . arena . alloc_from_iter ( branches. collect :: < Option < Vec < _ > > > ( ) ?) ,
78
- ) )
88
+ // We only want to use raw bytes in ValTrees for string slices or &[<integer_ty>]
89
+ let use_bytes_for_ref = |ty : Ty < ' tcx > | -> bool {
90
+ match ty. kind ( ) {
91
+ ty:: Str | ty:: Char | ty:: Uint ( _) | ty:: Int ( _) | ty:: Bool => true ,
92
+ _ => false ,
93
+ }
79
94
} ;
95
+
80
96
match place. layout . ty . kind ( ) {
81
97
ty:: FnDef ( ..) => Some ( ty:: ValTree :: zst ( ) ) ,
82
98
ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Char => {
@@ -90,19 +106,91 @@ fn const_to_valtree_inner<'tcx>(
90
106
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
91
107
// agree with runtime equality tests.
92
108
ty:: FnPtr ( _) | ty:: RawPtr ( _) => None ,
93
- ty:: Ref ( ..) => unimplemented ! ( "need to use deref_const" ) ,
109
+
110
+ ty:: Ref ( _, ref_ty, _) if place. layout . ty . is_slice ( ) => {
111
+ match ecx. try_read_immediate_from_mplace ( & place) {
112
+ Ok ( Some ( imm) ) => {
113
+ // `imm` is a ScalarPair. We try to get the underlying bytes behind that
114
+ // fat pointer for string slices and slices of integer types. For any other
115
+ // slice types we use `branches` to recursively construct the Valtree.
116
+
117
+ if use_bytes_for_ref ( * ref_ty) {
118
+ let ( alloc, range) = ecx. get_alloc_from_imm_scalar_pair ( imm) ;
119
+ let alloc_bytes = match alloc. get_bytes ( & ecx. tcx , range) {
120
+ Ok ( bytes) => bytes,
121
+ Err ( _e) => return None ,
122
+ } ;
123
+ debug ! ( ?alloc_bytes) ;
124
+
125
+ let bytes = ecx. tcx . arena . alloc_slice ( alloc_bytes) ;
126
+ let len = bytes. len ( ) ;
127
+ debug ! ( ?bytes, ?len) ;
128
+
129
+ let slice = ty:: ValSlice { bytes} ;
130
+
131
+ Some ( ty:: ValTree :: SliceOrStr ( slice) )
132
+ } else {
133
+ let derefd = ecx. deref_operand ( & imm. into ( ) ) . expect ( & format ! ( "couldnt deref {:?}" , imm) ) ;
134
+ debug ! ( "derefd: {:?}" , derefd) ;
135
+
136
+ let derefd_imm = match ecx. try_read_immediate_from_mplace ( & derefd) {
137
+ Ok ( Some ( imm) ) => imm,
138
+ _ => return None ,
139
+ } ;
140
+ debug ! ( ?derefd_imm) ;
141
+
142
+ let tcx = ecx. tcx . tcx ;
143
+ let scalar_len= derefd. meta . unwrap_meta ( ) ;
144
+ let len = match scalar_len {
145
+ Scalar :: Int ( int) => {
146
+ int. try_to_machine_usize ( tcx) . expect ( & format ! ( "Expected a valid ScalarInt in {:?}" , scalar_len) )
147
+ }
148
+ _ => bug ! ( "expected a ScalarInt in meta data for {:?}" , place) ,
149
+ } ;
150
+ debug ! ( ?len) ;
151
+
152
+ let valtree = branches ( ecx, place, len. try_into ( ) . expect ( "BLA" ) , None ) ;
153
+ debug ! ( ?valtree) ;
154
+
155
+ valtree
156
+ }
157
+ }
158
+ _ => {
159
+ None
160
+ }
161
+ }
162
+ }
163
+
164
+ ty:: Ref ( _, inner_ty, _) => {
165
+ debug ! ( "Ref with inner_ty: {:?}" , inner_ty) ;
166
+ let imm = ecx. try_read_immediate_from_mplace ( & place) . unwrap_or_else ( |e| bug ! ( "couldnt read immediate from {:?}, error: {:?}" , place, e) ) ;
167
+ match imm {
168
+ Some ( imm) => {
169
+ debug ! ( ?imm) ;
170
+
171
+ let derefd_place = ecx. deref_mplace ( place) . unwrap_or_else ( |e| bug ! ( "couldn't deref {:?}, error: {:?}" , place, e) ) ;
172
+ debug ! ( ?derefd_place) ;
173
+
174
+ const_to_valtree_inner ( ecx, & derefd_place)
175
+ }
176
+ None => None ,
177
+ }
178
+ }
179
+ ty:: Str => {
180
+ bug ! ( "ty::Str should have been handled in ty::Ref branch that uses raw bytes" ) ;
181
+ }
182
+ ty:: Slice ( _) => {
183
+ bug ! ( "should have been handled in the Ref arm" ) ;
184
+ }
94
185
95
186
// Trait objects are not allowed in type level constants, as we have no concept for
96
187
// resolving their backing type, even if we can do that at const eval time. We may
97
188
// hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
98
189
// but it is unclear if this is useful.
99
190
ty:: Dynamic ( ..) => None ,
100
191
101
- ty:: Slice ( _) | ty:: Str => {
102
- unimplemented ! ( "need to find the backing data of the slice/str and recurse on that" )
103
- }
104
- ty:: Tuple ( substs) => branches ( substs. len ( ) , None ) ,
105
- ty:: Array ( _, len) => branches ( usize:: try_from ( len. eval_usize ( ecx. tcx . tcx , ecx. param_env ) ) . unwrap ( ) , None ) ,
192
+ ty:: Tuple ( substs) => branches ( ecx, place, substs. len ( ) , None ) ,
193
+ ty:: Array ( _, len) => branches ( ecx, place, usize:: try_from ( len. eval_usize ( ecx. tcx . tcx , ecx. param_env ) ) . unwrap ( ) , None ) ,
106
194
107
195
ty:: Adt ( def, _) => {
108
196
if def. variants ( ) . is_empty ( ) {
@@ -111,7 +199,7 @@ fn const_to_valtree_inner<'tcx>(
111
199
112
200
let variant = ecx. read_discriminant ( & place. into ( ) ) . unwrap ( ) . 1 ;
113
201
114
- branches ( def. variant ( variant) . fields . len ( ) , def. is_enum ( ) . then_some ( variant) )
202
+ branches ( ecx , place , def. variant ( variant) . fields . len ( ) , def. is_enum ( ) . then_some ( variant) )
115
203
}
116
204
117
205
ty:: Never
0 commit comments