|
| 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