about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-04-04 09:27:47 -0700
committerGitHub <noreply@github.com>2023-04-04 09:27:47 -0700
commitb0483e80043f08a3af1e3390eb518e9218d86c4f (patch)
tree2423f64ac6f500d441ae528ad73855e059630a7d
parentd984671246f13a25c6bf69fed559e819686df85c (diff)
parentb5d96d5ec5388b89c700b4b9e6f7f73afa9cbcb1 (diff)
downloadrust-b0483e80043f08a3af1e3390eb518e9218d86c4f.tar.gz
rust-b0483e80043f08a3af1e3390eb518e9218d86c4f.zip
Rollup merge of #109938 - oli-obk:try_norm, r=compiler-errors
Move a const-prop-lint specific hack from mir interpret to const-prop-lint and make it fallible

fixes #109743

This hack didn't need to live in the mir interpreter. For const-prop-lint it is entirely correct to avoid doing any const prop if normalization fails at this stage. Most likely we couldn't const propagate anything anyway, and if revealing was needed (so opaque types were involved), we wouldn't want to be too smart and leak the hidden type anyway.
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs9
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs6
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs10
-rw-r--r--tests/ui/mir/issue-109743.rs51
4 files changed, 64 insertions, 12 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 8d5192bca67..5310ef0bb3e 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -612,14 +612,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         span: Option<Span>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        // FIXME(const_prop): normalization needed b/c const prop lint in
-        // `mir_drops_elaborated_and_const_checked`, which happens before
-        // optimized MIR. Only after optimizing the MIR can we guarantee
-        // that the `RevealAll` pass has happened and that the body's consts
-        // are normalized, so any call to resolve before that needs to be
-        // manually normalized.
-        let val = self.tcx.normalize_erasing_regions(self.param_env, *val);
-        match val {
+        match *val {
             mir::ConstantKind::Ty(ct) => {
                 let ty = ct.ty();
                 let valtree = self.eval_ty_constant(ct, span)?;
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 578cd82aa4c..7c59879a187 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -193,9 +193,9 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
         let arg = self.param_env.and(arg);
 
         self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
-                "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
-                arg.value
-            ))
+            "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
+            arg.value
+        ))
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index d7696a57000..176027b3b93 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -284,7 +284,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             return None;
         }
 
-        self.use_ecx(source_info, |this| this.ecx.eval_mir_constant(&c.literal, Some(c.span), None))
+        // Normalization needed b/c const prop lint runs in
+        // `mir_drops_elaborated_and_const_checked`, which happens before
+        // optimized MIR. Only after optimizing the MIR can we guarantee
+        // that the `RevealAll` pass has happened and that the body's consts
+        // are normalized, so any call to resolve before that needs to be
+        // manually normalized.
+        let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.literal).ok()?;
+
+        self.use_ecx(source_info, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None))
     }
 
     /// Returns the value, if any, of evaluating `place`.
diff --git a/tests/ui/mir/issue-109743.rs b/tests/ui/mir/issue-109743.rs
new file mode 100644
index 00000000000..73f3405e3ad
--- /dev/null
+++ b/tests/ui/mir/issue-109743.rs
@@ -0,0 +1,51 @@
+// build-pass
+// compile-flags: --crate-type=lib
+
+use std::marker::PhantomData;
+
+pub trait StreamOnce {
+    type Token;
+}
+
+impl StreamOnce for &str {
+    type Token = ();
+}
+
+pub trait Parser<Input: StreamOnce> {
+    type PartialState: Default;
+    fn parse_mode(&self, _state: &Self::PartialState) {}
+    fn parse_mode_impl() {}
+}
+
+pub fn parse_bool<'a>() -> impl Parser<&'a str> {
+    pub struct TokensCmp<C, Input>
+    where
+        Input: StreamOnce,
+    {
+        _cmp: C,
+        _marker: PhantomData<Input>,
+    }
+
+    impl<Input, C> Parser<Input> for TokensCmp<C, Input>
+    where
+        C: FnMut(Input::Token),
+        Input: StreamOnce,
+    {
+        type PartialState = ();
+    }
+
+    TokensCmp { _cmp: |_| (), _marker: PhantomData }
+}
+
+pub struct ParseBool;
+
+impl<'a> Parser<&'a str> for ParseBool
+where
+    &'a str: StreamOnce,
+{
+    type PartialState = ();
+
+    fn parse_mode_impl() {
+        parse_bool().parse_mode(&Default::default())
+    }
+}