|
| 1 | +use crate::thir::cx::region::Scope; |
1 | 2 | use crate::thir::cx::Cx;
|
2 | 3 | use crate::thir::util::UserAnnotatedTyHelpers;
|
3 | 4 | use rustc_data_structures::stack::ensure_sufficient_stack;
|
@@ -158,6 +159,98 @@ impl<'tcx> Cx<'tcx> {
|
158 | 159 | Expr { temp_lifetime, ty: adjustment.target, span, kind }
|
159 | 160 | }
|
160 | 161 |
|
| 162 | + /// Lowers a cast expression. |
| 163 | + /// |
| 164 | + /// Dealing with user type annotations is left to the caller. |
| 165 | + fn mirror_expr_cast( |
| 166 | + &mut self, |
| 167 | + source: &'tcx hir::Expr<'tcx>, |
| 168 | + temp_lifetime: Option<Scope>, |
| 169 | + span: Span, |
| 170 | + ) -> ExprKind<'tcx> { |
| 171 | + let tcx = self.tcx; |
| 172 | + |
| 173 | + // Check to see if this cast is a "coercion cast", where the cast is actually done |
| 174 | + // using a coercion (or is a no-op). |
| 175 | + if self.typeck_results().is_coercion_cast(source.hir_id) { |
| 176 | + // Convert the lexpr to a vexpr. |
| 177 | + ExprKind::Use { source: self.mirror_expr(source) } |
| 178 | + } else if self.typeck_results().expr_ty(source).is_region_ptr() { |
| 179 | + // Special cased so that we can type check that the element |
| 180 | + // type of the source matches the pointed to type of the |
| 181 | + // destination. |
| 182 | + ExprKind::Pointer { |
| 183 | + source: self.mirror_expr(source), |
| 184 | + cast: PointerCast::ArrayToPointer, |
| 185 | + } |
| 186 | + } else { |
| 187 | + // check whether this is casting an enum variant discriminant |
| 188 | + // to prevent cycles, we refer to the discriminant initializer |
| 189 | + // which is always an integer and thus doesn't need to know the |
| 190 | + // enum's layout (or its tag type) to compute it during const eval |
| 191 | + // Example: |
| 192 | + // enum Foo { |
| 193 | + // A, |
| 194 | + // B = A as isize + 4, |
| 195 | + // } |
| 196 | + // The correct solution would be to add symbolic computations to miri, |
| 197 | + // so we wouldn't have to compute and store the actual value |
| 198 | + |
| 199 | + let hir::ExprKind::Path(ref qpath) = source.kind else { |
| 200 | + return ExprKind::Cast { source: self.mirror_expr(source)}; |
| 201 | + }; |
| 202 | + |
| 203 | + let res = self.typeck_results().qpath_res(qpath, source.hir_id); |
| 204 | + let ty = self.typeck_results().node_type(source.hir_id); |
| 205 | + let ty::Adt(adt_def, substs) = ty.kind() else { |
| 206 | + return ExprKind::Cast { source: self.mirror_expr(source)}; |
| 207 | + }; |
| 208 | + |
| 209 | + let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res else { |
| 210 | + return ExprKind::Cast { source: self.mirror_expr(source)}; |
| 211 | + }; |
| 212 | + |
| 213 | + let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); |
| 214 | + let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx); |
| 215 | + |
| 216 | + use rustc_middle::ty::util::IntTypeExt; |
| 217 | + let ty = adt_def.repr().discr_type(); |
| 218 | + let discr_ty = ty.to_ty(tcx); |
| 219 | + |
| 220 | + let param_env_ty = self.param_env.and(discr_ty); |
| 221 | + let size = tcx |
| 222 | + .layout_of(param_env_ty) |
| 223 | + .unwrap_or_else(|e| { |
| 224 | + panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) |
| 225 | + }) |
| 226 | + .size; |
| 227 | + |
| 228 | + let lit = ScalarInt::try_from_uint(discr_offset as u128, size).unwrap(); |
| 229 | + let kind = ExprKind::NonHirLiteral { lit, user_ty: None }; |
| 230 | + let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); |
| 231 | + |
| 232 | + let source = match discr_did { |
| 233 | + // in case we are offsetting from a computed discriminant |
| 234 | + // and not the beginning of discriminants (which is always `0`) |
| 235 | + Some(did) => { |
| 236 | + let kind = ExprKind::NamedConst { def_id: did, substs, user_ty: None }; |
| 237 | + let lhs = |
| 238 | + self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); |
| 239 | + let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; |
| 240 | + self.thir.exprs.push(Expr { |
| 241 | + temp_lifetime, |
| 242 | + ty: discr_ty, |
| 243 | + span: span, |
| 244 | + kind: bin, |
| 245 | + }) |
| 246 | + } |
| 247 | + None => offset, |
| 248 | + }; |
| 249 | + |
| 250 | + ExprKind::Cast { source } |
| 251 | + } |
| 252 | + } |
| 253 | + |
161 | 254 | fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
|
162 | 255 | let tcx = self.tcx;
|
163 | 256 | let expr_ty = self.typeck_results().expr_ty(expr);
|
@@ -604,98 +697,7 @@ impl<'tcx> Cx<'tcx> {
|
604 | 697 | expr, cast_ty.hir_id, user_ty,
|
605 | 698 | );
|
606 | 699 |
|
607 |
| - // Check to see if this cast is a "coercion cast", where the cast is actually done |
608 |
| - // using a coercion (or is a no-op). |
609 |
| - let cast = if self.typeck_results().is_coercion_cast(source.hir_id) { |
610 |
| - // Convert the lexpr to a vexpr. |
611 |
| - ExprKind::Use { source: self.mirror_expr(source) } |
612 |
| - } else if self.typeck_results().expr_ty(source).is_region_ptr() { |
613 |
| - // Special cased so that we can type check that the element |
614 |
| - // type of the source matches the pointed to type of the |
615 |
| - // destination. |
616 |
| - ExprKind::Pointer { |
617 |
| - source: self.mirror_expr(source), |
618 |
| - cast: PointerCast::ArrayToPointer, |
619 |
| - } |
620 |
| - } else { |
621 |
| - // check whether this is casting an enum variant discriminant |
622 |
| - // to prevent cycles, we refer to the discriminant initializer |
623 |
| - // which is always an integer and thus doesn't need to know the |
624 |
| - // enum's layout (or its tag type) to compute it during const eval |
625 |
| - // Example: |
626 |
| - // enum Foo { |
627 |
| - // A, |
628 |
| - // B = A as isize + 4, |
629 |
| - // } |
630 |
| - // The correct solution would be to add symbolic computations to miri, |
631 |
| - // so we wouldn't have to compute and store the actual value |
632 |
| - let var = if let hir::ExprKind::Path(ref qpath) = source.kind { |
633 |
| - let res = self.typeck_results().qpath_res(qpath, source.hir_id); |
634 |
| - self.typeck_results().node_type(source.hir_id).ty_adt_def().and_then( |
635 |
| - |adt_def| match res { |
636 |
| - Res::Def( |
637 |
| - DefKind::Ctor(CtorOf::Variant, CtorKind::Const), |
638 |
| - variant_ctor_id, |
639 |
| - ) => { |
640 |
| - let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); |
641 |
| - let (d, o) = adt_def.discriminant_def_for_variant(idx); |
642 |
| - use rustc_middle::ty::util::IntTypeExt; |
643 |
| - let ty = adt_def.repr().discr_type(); |
644 |
| - let ty = ty.to_ty(tcx); |
645 |
| - Some((d, o, ty)) |
646 |
| - } |
647 |
| - _ => None, |
648 |
| - }, |
649 |
| - ) |
650 |
| - } else { |
651 |
| - None |
652 |
| - }; |
653 |
| - |
654 |
| - let source = if let Some((did, offset, var_ty)) = var { |
655 |
| - let param_env_ty = self.param_env.and(var_ty); |
656 |
| - let size = tcx |
657 |
| - .layout_of(param_env_ty) |
658 |
| - .unwrap_or_else(|e| { |
659 |
| - panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) |
660 |
| - }) |
661 |
| - .size; |
662 |
| - let lit = ScalarInt::try_from_uint(offset as u128, size).unwrap(); |
663 |
| - let kind = ExprKind::NonHirLiteral { lit, user_ty: None }; |
664 |
| - let offset = self.thir.exprs.push(Expr { |
665 |
| - temp_lifetime, |
666 |
| - ty: var_ty, |
667 |
| - span: expr.span, |
668 |
| - kind, |
669 |
| - }); |
670 |
| - match did { |
671 |
| - Some(did) => { |
672 |
| - // in case we are offsetting from a computed discriminant |
673 |
| - // and not the beginning of discriminants (which is always `0`) |
674 |
| - let substs = InternalSubsts::identity_for_item(tcx, did); |
675 |
| - let kind = |
676 |
| - ExprKind::NamedConst { def_id: did, substs, user_ty: None }; |
677 |
| - let lhs = self.thir.exprs.push(Expr { |
678 |
| - temp_lifetime, |
679 |
| - ty: var_ty, |
680 |
| - span: expr.span, |
681 |
| - kind, |
682 |
| - }); |
683 |
| - let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; |
684 |
| - self.thir.exprs.push(Expr { |
685 |
| - temp_lifetime, |
686 |
| - ty: var_ty, |
687 |
| - span: expr.span, |
688 |
| - kind: bin, |
689 |
| - }) |
690 |
| - } |
691 |
| - None => offset, |
692 |
| - } |
693 |
| - } else { |
694 |
| - self.mirror_expr(source) |
695 |
| - }; |
696 |
| - |
697 |
| - ExprKind::Cast { source: source } |
698 |
| - }; |
| 700 | + let cast = self.mirror_expr_cast(*source, temp_lifetime, expr.span); |
699 | 701 |
|
700 | 702 | if let Some(user_ty) = user_ty {
|
701 | 703 | // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
|
|
0 commit comments