From 4c4fb7152bf73dcbdd0066e65ec3d034d42589c5 Mon Sep 17 00:00:00 2001 From: b-naber Date: Thu, 23 Jun 2022 17:34:34 +0200 Subject: [PATCH 1/5] add test --- src/test/ui/const-generics/issues/issue-97634.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-97634.rs diff --git a/src/test/ui/const-generics/issues/issue-97634.rs b/src/test/ui/const-generics/issues/issue-97634.rs new file mode 100644 index 0000000000000..a04036d0647ad --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-97634.rs @@ -0,0 +1,10 @@ +//build-pass + +pub enum Register { + Field0 = 40, + Field1, +} + +fn main() { + let _b = Register::<0>::Field1 as u16; +} From 2e3221a927ed77e81652fafa5256335212755e60 Mon Sep 17 00:00:00 2001 From: b-naber Date: Thu, 23 Jun 2022 17:34:17 +0200 Subject: [PATCH 2/5] use correct substs in enum discriminant hack --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index fb2f5861c6f03..38c4f94ed12cf 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -650,6 +650,9 @@ impl<'tcx> Cx<'tcx> { } else { None }; + debug!(?var); + let substs = self.typeck_results.node_substs(source.hir_id); + debug!(?substs); let source = if let Some((did, offset, var_ty)) = var { let param_env_ty = self.param_env.and(var_ty); @@ -671,7 +674,7 @@ impl<'tcx> Cx<'tcx> { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) - let substs = InternalSubsts::identity_for_item(tcx, did); + let kind = ExprKind::NamedConst { def_id: did, substs, user_ty: None }; let lhs = self.thir.exprs.push(Expr { From 38814fc03900c2adceb021472027aed28b5714ed Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 24 Jun 2022 13:19:23 +0200 Subject: [PATCH 3/5] small refactor --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 191 ++++++++++--------- 1 file changed, 96 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 38c4f94ed12cf..3f854554f4d04 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,3 +1,4 @@ +use crate::thir::cx::region::Scope; use crate::thir::cx::Cx; use crate::thir::util::UserAnnotatedTyHelpers; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -158,6 +159,100 @@ impl<'tcx> Cx<'tcx> { Expr { temp_lifetime, ty: adjustment.target, span, kind } } + fn mirror_expr_cast( + &mut self, + source: &'tcx hir::Expr<'tcx>, + temp_lifetime: Option, + span: Span, + ) -> ExprKind<'tcx> { + let tcx = self.tcx; + + // Check to see if this cast is a "coercion cast", where the cast is actually done + // using a coercion (or is a no-op). + if self.typeck_results().is_coercion_cast(source.hir_id) { + // Convert the lexpr to a vexpr. + ExprKind::Use { source: self.mirror_expr(source) } + } else if self.typeck_results().expr_ty(source).is_region_ptr() { + // Special cased so that we can type check that the element + // type of the source matches the pointed to type of the + // destination. + ExprKind::Pointer { + source: self.mirror_expr(source), + cast: PointerCast::ArrayToPointer, + } + } else { + // check whether this is casting an enum variant discriminant + // to prevent cycles, we refer to the discriminant initializer + // which is always an integer and thus doesn't need to know the + // enum's layout (or its tag type) to compute it during const eval + // Example: + // enum Foo { + // A, + // B = A as isize + 4, + // } + // The correct solution would be to add symbolic computations to miri, + // so we wouldn't have to compute and store the actual value + + let hir::ExprKind::Path(ref qpath) = source.kind else { + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; + + let res = self.typeck_results().qpath_res(qpath, source.hir_id); + let (discr_did, discr_offset, discr_ty, substs) = { + let ty = self.typeck_results().node_type(source.hir_id); + let ty::Adt(adt_def, substs) = ty.kind() else { + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; + let Res::Def( + DefKind::Ctor(CtorOf::Variant, CtorKind::Const), + variant_ctor_id, + ) = res else { + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; + + let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); + let (d, o) = adt_def.discriminant_def_for_variant(idx); + use rustc_middle::ty::util::IntTypeExt; + let ty = adt_def.repr().discr_type(); + let ty = ty.to_ty(tcx); + (d, o, ty, substs) + }; + + let param_env_ty = self.param_env.and(discr_ty); + let size = tcx + .layout_of(param_env_ty) + .unwrap_or_else(|e| { + panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) + }) + .size; + + let lit = ScalarInt::try_from_uint(discr_offset as u128, size).unwrap(); + let kind = ExprKind::NonHirLiteral { lit, user_ty: None }; + let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); + + let source = match discr_did { + Some(did) => { + // in case we are offsetting from a computed discriminant + // and not the beginning of discriminants (which is always `0`) + + let kind = ExprKind::NamedConst { def_id: did, substs, user_ty: None }; + let lhs = + self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); + let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; + self.thir.exprs.push(Expr { + temp_lifetime, + ty: discr_ty, + span: span, + kind: bin, + }) + } + None => offset, + }; + + ExprKind::Cast { source } + } + } + fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); @@ -604,101 +699,7 @@ impl<'tcx> Cx<'tcx> { expr, cast_ty.hir_id, user_ty, ); - // Check to see if this cast is a "coercion cast", where the cast is actually done - // using a coercion (or is a no-op). - let cast = if self.typeck_results().is_coercion_cast(source.hir_id) { - // Convert the lexpr to a vexpr. - ExprKind::Use { source: self.mirror_expr(source) } - } else if self.typeck_results().expr_ty(source).is_region_ptr() { - // Special cased so that we can type check that the element - // type of the source matches the pointed to type of the - // destination. - ExprKind::Pointer { - source: self.mirror_expr(source), - cast: PointerCast::ArrayToPointer, - } - } else { - // check whether this is casting an enum variant discriminant - // to prevent cycles, we refer to the discriminant initializer - // which is always an integer and thus doesn't need to know the - // enum's layout (or its tag type) to compute it during const eval - // Example: - // enum Foo { - // A, - // B = A as isize + 4, - // } - // The correct solution would be to add symbolic computations to miri, - // so we wouldn't have to compute and store the actual value - let var = if let hir::ExprKind::Path(ref qpath) = source.kind { - let res = self.typeck_results().qpath_res(qpath, source.hir_id); - self.typeck_results().node_type(source.hir_id).ty_adt_def().and_then( - |adt_def| match res { - Res::Def( - DefKind::Ctor(CtorOf::Variant, CtorKind::Const), - variant_ctor_id, - ) => { - let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); - let (d, o) = adt_def.discriminant_def_for_variant(idx); - use rustc_middle::ty::util::IntTypeExt; - let ty = adt_def.repr().discr_type(); - let ty = ty.to_ty(tcx); - Some((d, o, ty)) - } - _ => None, - }, - ) - } else { - None - }; - debug!(?var); - let substs = self.typeck_results.node_substs(source.hir_id); - debug!(?substs); - - let source = if let Some((did, offset, var_ty)) = var { - let param_env_ty = self.param_env.and(var_ty); - let size = tcx - .layout_of(param_env_ty) - .unwrap_or_else(|e| { - panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) - }) - .size; - let lit = ScalarInt::try_from_uint(offset as u128, size).unwrap(); - let kind = ExprKind::NonHirLiteral { lit, user_ty: None }; - let offset = self.thir.exprs.push(Expr { - temp_lifetime, - ty: var_ty, - span: expr.span, - kind, - }); - match did { - Some(did) => { - // in case we are offsetting from a computed discriminant - // and not the beginning of discriminants (which is always `0`) - - let kind = - ExprKind::NamedConst { def_id: did, substs, user_ty: None }; - let lhs = self.thir.exprs.push(Expr { - temp_lifetime, - ty: var_ty, - span: expr.span, - kind, - }); - let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; - self.thir.exprs.push(Expr { - temp_lifetime, - ty: var_ty, - span: expr.span, - kind: bin, - }) - } - None => offset, - } - } else { - self.mirror_expr(source) - }; - - ExprKind::Cast { source: source } - }; + let cast = self.mirror_expr_cast(*source, temp_lifetime, expr.span); if let Some(user_ty) = user_ty { // NOTE: Creating a new Expr and wrapping a Cast inside of it may be From f39c0d6b0a7b80959956a6e006dfc3406f8141e3 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 24 Jun 2022 13:43:56 +0200 Subject: [PATCH 4/5] address review --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 3f854554f4d04..b127b264b834f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -159,6 +159,9 @@ impl<'tcx> Cx<'tcx> { Expr { temp_lifetime, ty: adjustment.target, span, kind } } + /// Lowers a cast expression. + /// + /// Dealing with user type annotations is left to the caller. fn mirror_expr_cast( &mut self, source: &'tcx hir::Expr<'tcx>, @@ -198,25 +201,23 @@ impl<'tcx> Cx<'tcx> { }; let res = self.typeck_results().qpath_res(qpath, source.hir_id); - let (discr_did, discr_offset, discr_ty, substs) = { - let ty = self.typeck_results().node_type(source.hir_id); - let ty::Adt(adt_def, substs) = ty.kind() else { + let ty = self.typeck_results().node_type(source.hir_id); + let ty::Adt(adt_def, substs) = ty.kind() else { return ExprKind::Cast { source: self.mirror_expr(source)}; }; - let Res::Def( + let Res::Def( DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id, ) = res else { return ExprKind::Cast { source: self.mirror_expr(source)}; }; - let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); - let (d, o) = adt_def.discriminant_def_for_variant(idx); - use rustc_middle::ty::util::IntTypeExt; - let ty = adt_def.repr().discr_type(); - let ty = ty.to_ty(tcx); - (d, o, ty, substs) - }; + let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); + let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx); + + use rustc_middle::ty::util::IntTypeExt; + let ty = adt_def.repr().discr_type(); + let discr_ty = ty.to_ty(tcx); let param_env_ty = self.param_env.and(discr_ty); let size = tcx @@ -231,10 +232,9 @@ impl<'tcx> Cx<'tcx> { let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); let source = match discr_did { + // in case we are offsetting from a computed discriminant + // and not the beginning of discriminants (which is always `0`) Some(did) => { - // in case we are offsetting from a computed discriminant - // and not the beginning of discriminants (which is always `0`) - let kind = ExprKind::NamedConst { def_id: did, substs, user_ty: None }; let lhs = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); From bf48b622a5ff7efc16ac099bbe8d272445a49d70 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 24 Jun 2022 16:43:38 +0200 Subject: [PATCH 5/5] fmt --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 14 ++++++-------- src/test/ui/const-generics/issues/issue-97634.rs | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b127b264b834f..a0878c97e883f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -203,14 +203,12 @@ impl<'tcx> Cx<'tcx> { let res = self.typeck_results().qpath_res(qpath, source.hir_id); let ty = self.typeck_results().node_type(source.hir_id); let ty::Adt(adt_def, substs) = ty.kind() else { - return ExprKind::Cast { source: self.mirror_expr(source)}; - }; - let Res::Def( - DefKind::Ctor(CtorOf::Variant, CtorKind::Const), - variant_ctor_id, - ) = res else { - return ExprKind::Cast { source: self.mirror_expr(source)}; - }; + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; + + let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res else { + return ExprKind::Cast { source: self.mirror_expr(source)}; + }; let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx); diff --git a/src/test/ui/const-generics/issues/issue-97634.rs b/src/test/ui/const-generics/issues/issue-97634.rs index a04036d0647ad..422e8de685645 100644 --- a/src/test/ui/const-generics/issues/issue-97634.rs +++ b/src/test/ui/const-generics/issues/issue-97634.rs @@ -1,4 +1,4 @@ -//build-pass +// build-pass pub enum Register { Field0 = 40,