From ad5aa2359d45654953405763090dbc0cd63b0c97 Mon Sep 17 00:00:00 2001
From: oli <github35764891676564198441@oli-obk.de>
Date: Mon, 4 Jan 2021 23:32:19 +0000
Subject: [PATCH 1/3] Remove an unnecessary field from a `NonConstOp`

---
 compiler/rustc_mir/src/transform/check_consts/ops.rs        | 2 +-
 compiler/rustc_mir/src/transform/check_consts/validation.rs | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 9e90a7519cf..99ffb0edce9 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -72,7 +72,7 @@ impl NonConstOp for FnCallIndirect {
 
 /// A function call where the callee is not marked as `const`.
 #[derive(Debug)]
-pub struct FnCallNonConst(pub DefId);
+pub struct FnCallNonConst;
 impl NonConstOp for FnCallNonConst {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index d1c07d1051d..ebb4e7e7fa0 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -817,7 +817,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 // Attempting to call a trait method?
                 if let Some(trait_id) = tcx.trait_of_item(callee) {
                     if !self.tcx.features().const_trait_impl {
-                        self.check_op(ops::FnCallNonConst(callee));
+                        self.check_op(ops::FnCallNonConst);
                         return;
                     }
 
@@ -883,7 +883,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 }
 
                 if !tcx.is_const_fn_raw(callee) {
-                    self.check_op(ops::FnCallNonConst(callee));
+                    self.check_op(ops::FnCallNonConst);
                     return;
                 }
 

From 949bdd8b79a48ac25408f9cfb0e9d57a75d5f12b Mon Sep 17 00:00:00 2001
From: oli <github35764891676564198441@oli-obk.de>
Date: Mon, 4 Jan 2021 23:01:58 +0000
Subject: [PATCH 2/3] Add regression test

---
 .../src/transform/check_consts/validation.rs  | 20 ++++++++++++++-----
 .../ui/consts/intrinsic_without_const_stab.rs | 20 +++++++++++++++++++
 .../intrinsic_without_const_stab_fail.rs      | 15 ++++++++++++++
 .../intrinsic_without_const_stab_fail.stderr  |  9 +++++++++
 4 files changed, 59 insertions(+), 5 deletions(-)
 create mode 100644 src/test/ui/consts/intrinsic_without_const_stab.rs
 create mode 100644 src/test/ui/consts/intrinsic_without_const_stab_fail.rs
 create mode 100644 src/test/ui/consts/intrinsic_without_const_stab_fail.stderr

diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index ebb4e7e7fa0..ca7c393d4af 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -789,10 +789,10 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
         }
     }
 
+    #[instrument(skip(self))]
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         use rustc_target::spec::abi::Abi::RustIntrinsic;
 
-        trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
@@ -816,6 +816,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
 
                 // Attempting to call a trait method?
                 if let Some(trait_id) = tcx.trait_of_item(callee) {
+                    trace!("attempting to call a trait method");
                     if !self.tcx.features().const_trait_impl {
                         self.check_op(ops::FnCallNonConst);
                         return;
@@ -871,13 +872,13 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                     return;
                 }
 
+                let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
+
                 // HACK: This is to "unstabilize" the `transmute` intrinsic
                 // within const fns. `transmute` is allowed in all other const contexts.
                 // This won't really scale to more intrinsics or functions. Let's allow const
                 // transmutes in const fn before we add more hacks to this.
-                if tcx.fn_sig(callee).abi() == RustIntrinsic
-                    && tcx.item_name(callee) == sym::transmute
-                {
+                if is_intrinsic && tcx.item_name(callee) == sym::transmute {
                     self.check_op(ops::Transmute);
                     return;
                 }
@@ -890,6 +891,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 // If the `const fn` we are trying to call is not const-stable, ensure that we have
                 // the proper feature gate enabled.
                 if let Some(gate) = is_unstable_const_fn(tcx, callee) {
+                    trace!(?gate, "calling unstable const fn");
                     if self.span.allows_unstable(gate) {
                         return;
                     }
@@ -904,12 +906,14 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                     // If this crate is not using stability attributes, or the caller is not claiming to be a
                     // stable `const fn`, that is all that is required.
                     if !self.ccx.is_const_stable_const_fn() {
+                        trace!("crate not using stability attributes or caller not stably const");
                         return;
                     }
 
                     // Otherwise, we are something const-stable calling a const-unstable fn.
 
                     if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
+                        trace!("rustc_allow_const_fn_unstable gate active");
                         return;
                     }
 
@@ -923,10 +927,16 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
                     && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
                 if callee_is_unstable_unmarked {
-                    if self.ccx.is_const_stable_const_fn() {
+                    trace!("callee_is_unstable_unmarked");
+                    // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
+                    // `extern` funtions, and these have way to get marked `const`. So instead we
+                    // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
+                    if self.ccx.is_const_stable_const_fn() || is_intrinsic {
                         self.check_op(ops::FnCallUnstable(callee, None));
+                        return;
                     }
                 }
+                trace!("permitting call");
             }
 
             // Forbid all `Drop` terminators unless the place being dropped is a local with no
diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs
new file mode 100644
index 00000000000..8f71cd26e5f
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(intrinsics, staged_api, const_intrinsic_copy)]
+#![stable(feature = "core", since = "1.6.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[inline]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+    extern "rust-intrinsic" {
+        fn copy<T>(src: *const T, dst: *mut T, count: usize);
+    }
+
+    // Even though the `copy` intrinsic lacks stability attributes, this works, because it
+    // inherits its stability attributes from its parent. That includes `rustc_const_(un)stable`
+    // attributes.
+    unsafe { copy(src, dst, count) }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.rs b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs
new file mode 100644
index 00000000000..bf2c44169d4
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.rs
@@ -0,0 +1,15 @@
+#![feature(intrinsics, staged_api, const_intrinsic_copy)]
+#![stable(feature = "core", since = "1.6.0")]
+
+extern "rust-intrinsic" {
+    fn copy<T>(src: *const T, dst: *mut T, count: usize);
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[inline]
+pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
+    unsafe { copy(src, dst, count) } //~ ERROR calls in constant functions are limited
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
new file mode 100644
index 00000000000..d4a2989e785
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
@@ -0,0 +1,9 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/intrinsic_without_const_stab_fail.rs:12:14
+   |
+LL |     unsafe { copy(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.

From 5bac1c9229331105bab558f7d3be1685a76d110c Mon Sep 17 00:00:00 2001
From: oli <github35764891676564198441@oli-obk.de>
Date: Sat, 16 Jan 2021 19:59:21 +0000
Subject: [PATCH 3/3] Only inherit const stability for methods of `impl const
 Trait` blocks

---
 .../src/transform/check_consts/validation.rs  |  2 +-
 compiler/rustc_passes/src/stability.rs        | 70 ++++++++++++++++---
 library/core/src/intrinsics.rs                |  2 +
 .../ui/consts/intrinsic_without_const_stab.rs |  7 +-
 .../intrinsic_without_const_stab.stderr       |  9 +++
 5 files changed, 74 insertions(+), 16 deletions(-)
 create mode 100644 src/test/ui/consts/intrinsic_without_const_stab.stderr

diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index ca7c393d4af..e884454f5c6 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -929,7 +929,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 if callee_is_unstable_unmarked {
                     trace!("callee_is_unstable_unmarked");
                     // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
-                    // `extern` funtions, and these have way to get marked `const`. So instead we
+                    // `extern` funtions, and these have no way to get marked `const`. So instead we
                     // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
                     if self.ccx.is_const_stable_const_fn() || is_intrinsic {
                         self.check_op(ops::FnCallUnstable(callee, None));
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 4a3d6ecf8cc..b70cec25dfb 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -55,6 +55,21 @@ impl InheritDeprecation {
     }
 }
 
+/// Whether to inherit const stability flags for nested items. In most cases, we do not want to
+/// inherit const stability: just because an enclosing `fn` is const-stable does not mean
+/// all `extern` imports declared in it should be const-stable! However, trait methods
+/// inherit const stability attributes from their parent and do not have their own.
+enum InheritConstStability {
+    Yes,
+    No,
+}
+
+impl InheritConstStability {
+    fn yes(&self) -> bool {
+        matches!(self, InheritConstStability::Yes)
+    }
+}
+
 // A private tree-walker for producing an Index.
 struct Annotator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -75,6 +90,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         item_sp: Span,
         kind: AnnotationKind,
         inherit_deprecation: InheritDeprecation,
+        inherit_const_stability: InheritConstStability,
         visit_children: F,
     ) where
         F: FnOnce(&mut Self),
@@ -140,6 +156,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             const_stab
         });
 
+        // `impl const Trait for Type` items forward their const stability to their
+        // immediate children.
         if const_stab.is_none() {
             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
             if let Some(parent) = self.parent_const_stab {
@@ -228,7 +246,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         self.recurse_with_stability_attrs(
             depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
             stab,
-            const_stab,
+            if inherit_const_stability.yes() { const_stab } else { None },
             visit_children,
         );
     }
@@ -325,6 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
         let orig_in_trait_impl = self.in_trait_impl;
         let mut kind = AnnotationKind::Required;
+        let mut const_stab_inherit = InheritConstStability::No;
         match i.kind {
             // Inherent impls and foreign modules serve only as containers for other items,
             // they don't have their own stability. They still can be annotated as unstable
@@ -338,6 +357,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
                 self.in_trait_impl = true;
                 kind = AnnotationKind::DeprecationProhibited;
+                const_stab_inherit = InheritConstStability::Yes;
             }
             hir::ItemKind::Struct(ref sd, _) => {
                 if let Some(ctor_hir_id) = sd.ctor_hir_id() {
@@ -347,6 +367,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
                         i.span,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
+                        InheritConstStability::No,
                         |_| {},
                     )
                 }
@@ -354,9 +375,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             _ => {}
         }
 
-        self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| {
-            intravisit::walk_item(v, i)
-        });
+        self.annotate(
+            i.hir_id,
+            &i.attrs,
+            i.span,
+            kind,
+            InheritDeprecation::Yes,
+            const_stab_inherit,
+            |v| intravisit::walk_item(v, i),
+        );
         self.in_trait_impl = orig_in_trait_impl;
     }
 
@@ -367,6 +394,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             ti.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 intravisit::walk_trait_item(v, ti);
             },
@@ -376,9 +404,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         let kind =
             if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
-        self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| {
-            intravisit::walk_impl_item(v, ii);
-        });
+        self.annotate(
+            ii.hir_id,
+            &ii.attrs,
+            ii.span,
+            kind,
+            InheritDeprecation::Yes,
+            InheritConstStability::No,
+            |v| {
+                intravisit::walk_impl_item(v, ii);
+            },
+        );
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
@@ -388,6 +424,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             var.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
                     v.annotate(
@@ -396,6 +433,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
                         var.span,
                         AnnotationKind::Required,
                         InheritDeprecation::Yes,
+                        InheritConstStability::No,
                         |_| {},
                     );
                 }
@@ -412,6 +450,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             s.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 intravisit::walk_struct_field(v, s);
             },
@@ -425,6 +464,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             i.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| {
                 intravisit::walk_foreign_item(v, i);
             },
@@ -438,6 +478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             md.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |_| {},
         );
     }
@@ -451,9 +492,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             _ => AnnotationKind::Prohibited,
         };
 
-        self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| {
-            intravisit::walk_generic_param(v, p);
-        });
+        self.annotate(
+            p.hir_id,
+            &p.attrs,
+            p.span,
+            kind,
+            InheritDeprecation::No,
+            InheritConstStability::No,
+            |v| {
+                intravisit::walk_generic_param(v, p);
+            },
+        );
     }
 }
 
@@ -618,6 +667,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
             krate.item.span,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
+            InheritConstStability::No,
             |v| intravisit::walk_crate(v, krate),
         );
     }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index fa5f0d50400..7c1a9b82f99 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1842,6 +1842,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 #[inline]
 pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
         fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
 
@@ -1926,6 +1927,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
 #[inline]
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
 
diff --git a/src/test/ui/consts/intrinsic_without_const_stab.rs b/src/test/ui/consts/intrinsic_without_const_stab.rs
index 8f71cd26e5f..810158a2957 100644
--- a/src/test/ui/consts/intrinsic_without_const_stab.rs
+++ b/src/test/ui/consts/intrinsic_without_const_stab.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(intrinsics, staged_api, const_intrinsic_copy)]
 #![stable(feature = "core", since = "1.6.0")]
 
@@ -7,14 +5,13 @@
 #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
 #[inline]
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+    // Const stability attributes are not inherited from parent items.
     extern "rust-intrinsic" {
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    // Even though the `copy` intrinsic lacks stability attributes, this works, because it
-    // inherits its stability attributes from its parent. That includes `rustc_const_(un)stable`
-    // attributes.
     unsafe { copy(src, dst, count) }
+    //~^ ERROR calls in constant functions are limited to constant functions
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/intrinsic_without_const_stab.stderr b/src/test/ui/consts/intrinsic_without_const_stab.stderr
new file mode 100644
index 00000000000..5a42823a605
--- /dev/null
+++ b/src/test/ui/consts/intrinsic_without_const_stab.stderr
@@ -0,0 +1,9 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/intrinsic_without_const_stab.rs:13:14
+   |
+LL |     unsafe { copy(src, dst, count) }
+   |              ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.