From 9f8a6be22188b1ac666bae83fc6aaf7f84ba4522 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Thu, 24 Oct 2024 22:47:45 +1100
Subject: [PATCH 01/13] coverage: Consolidate creation of covmap/covfun records

There is no need for this code to be split across multiple functions in
multiple files.
---
 .../src/coverageinfo/mapgen.rs                | 83 ++++++++++++++-----
 .../src/coverageinfo/mod.rs                   | 69 +--------------
 2 files changed, 64 insertions(+), 88 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 61e474031bb08..b69ca62341340 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,7 +1,10 @@
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
 
 use itertools::Itertools as _;
-use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
+use rustc_abi::Align;
+use rustc_codegen_ssa::traits::{
+    BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
+};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::IndexVec;
@@ -10,6 +13,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::Symbol;
 use rustc_span::def_id::DefIdSet;
+use rustc_target::spec::HasTargetSpec;
 use tracing::debug;
 
 use crate::common::CodegenCx;
@@ -78,8 +82,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
 
     // Generate the coverage map header, which contains the filenames used by
     // this CGU's coverage mappings, and store it in a well-known global.
-    let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val);
-    coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
+    generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
 
     let mut unused_function_names = Vec::new();
     let covfun_section_name = coverageinfo::covfun_section_name(cx);
@@ -111,7 +114,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
             unused_function_names.push(mangled_function_name);
         }
 
-        save_function_record(
+        generate_covfun_record(
             cx,
             &covfun_section_name,
             mangled_function_name,
@@ -308,15 +311,15 @@ fn encode_mappings_for_function(
     })
 }
 
-/// Construct coverage map header and the array of function records, and combine them into the
-/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
-/// specific, well-known section and name.
-fn generate_coverage_map<'ll>(
+/// Generates the contents of the covmap record for this CGU, which mostly
+/// consists of a header and a list of filenames. The record is then stored
+/// as a global variable in the `__llvm_covmap` section.
+fn generate_covmap_record<'ll>(
     cx: &CodegenCx<'ll, '_>,
     version: u32,
     filenames_size: usize,
     filenames_val: &'ll llvm::Value,
-) -> &'ll llvm::Value {
+) {
     debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
 
     // Create the coverage data header (Note, fields 0 and 2 are now always zero,
@@ -331,13 +334,35 @@ fn generate_coverage_map<'ll>(
     );
 
     // Create the complete LLVM coverage data value to add to the LLVM IR
-    cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
+    let covmap_data =
+        cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
+
+    let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
+        llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
+    }))
+    .unwrap();
+    debug!("covmap var name: {:?}", covmap_var_name);
+
+    let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
+        llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
+    }))
+    .expect("covmap section name should not contain NUL");
+    debug!("covmap section name: {:?}", covmap_section_name);
+
+    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name);
+    llvm::set_initializer(llglobal, covmap_data);
+    llvm::set_global_constant(llglobal, true);
+    llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
+    llvm::set_section(llglobal, &covmap_section_name);
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    llvm::set_alignment(llglobal, Align::EIGHT);
+    cx.add_used_global(llglobal);
 }
 
-/// Construct a function record and combine it with the function's coverage mapping data.
-/// Save the function record into the LLVM IR as a static global using a
-/// specific, well-known section and name.
-fn save_function_record(
+/// Generates the contents of the covfun record for this function, which
+/// contains the function's coverage mapping data. The record is then stored
+/// as a global variable in the `__llvm_covfun` section.
+fn generate_covfun_record(
     cx: &CodegenCx<'_, '_>,
     covfun_section_name: &CStr,
     mangled_function_name: &str,
@@ -366,13 +391,27 @@ fn save_function_record(
         /*packed=*/ true,
     );
 
-    coverageinfo::save_func_record_to_mod(
-        cx,
-        covfun_section_name,
-        func_name_hash,
-        func_record_val,
-        is_used,
-    );
+    // Choose a variable name to hold this function's covfun data.
+    // Functions that are used have a suffix ("u") to distinguish them from
+    // unused copies of the same function (from different CGUs), so that if a
+    // linker sees both it won't discard the used copy's data.
+    let func_record_var_name =
+        CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
+            .unwrap();
+    debug!("function record var name: {:?}", func_record_var_name);
+
+    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
+    llvm::set_initializer(llglobal, func_record_val);
+    llvm::set_global_constant(llglobal, true);
+    llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
+    llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
+    llvm::set_section(llglobal, covfun_section_name);
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    llvm::set_alignment(llglobal, Align::EIGHT);
+    if cx.target_spec().supports_comdat() {
+        llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
+    }
+    cx.add_used_global(llglobal);
 }
 
 /// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index b2956945911b1..58607ce7497ff 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,10 +1,9 @@
 use std::cell::RefCell;
-use std::ffi::{CStr, CString};
+use std::ffi::CString;
 
 use libc::c_uint;
 use rustc_codegen_ssa::traits::{
-    BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods,
-    MiscCodegenMethods, StaticCodegenMethods,
+    BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
 };
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_llvm::RustString;
@@ -12,8 +11,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_target::abi::{Align, Size};
-use rustc_target::spec::HasTargetSpec;
+use rustc_target::abi::Size;
 use tracing::{debug, instrument};
 
 use crate::builder::Builder;
@@ -290,67 +288,6 @@ pub(crate) fn mapping_version() -> u32 {
     unsafe { llvm::LLVMRustCoverageMappingVersion() }
 }
 
-pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    cov_data_val: &'ll llvm::Value,
-) {
-    let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
-        llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
-    }))
-    .unwrap();
-    debug!("covmap var name: {:?}", covmap_var_name);
-
-    let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
-        llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
-    }))
-    .expect("covmap section name should not contain NUL");
-    debug!("covmap section name: {:?}", covmap_section_name);
-
-    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
-    llvm::set_initializer(llglobal, cov_data_val);
-    llvm::set_global_constant(llglobal, true);
-    llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
-    llvm::set_section(llglobal, &covmap_section_name);
-    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
-    llvm::set_alignment(llglobal, Align::EIGHT);
-    cx.add_used_global(llglobal);
-}
-
-pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    covfun_section_name: &CStr,
-    func_name_hash: u64,
-    func_record_val: &'ll llvm::Value,
-    is_used: bool,
-) {
-    // Assign a name to the function record. This is used to merge duplicates.
-    //
-    // In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
-    // are included-but-not-used. If (or when) Rust generates functions that are
-    // included-but-not-used, note that a dummy description for a function included-but-not-used
-    // in a Crate can be replaced by full description provided by a different Crate. The two kinds
-    // of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
-    // appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
-    let func_record_var_name =
-        CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
-            .unwrap();
-    debug!("function record var name: {:?}", func_record_var_name);
-    debug!("function record section name: {:?}", covfun_section_name);
-
-    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
-    llvm::set_initializer(llglobal, func_record_val);
-    llvm::set_global_constant(llglobal, true);
-    llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
-    llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
-    llvm::set_section(llglobal, covfun_section_name);
-    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
-    llvm::set_alignment(llglobal, Align::EIGHT);
-    if cx.target_spec().supports_comdat() {
-        llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
-    }
-    cx.add_used_global(llglobal);
-}
-
 /// Returns the section name string to pass through to the linker when embedding
 /// per-function coverage information in the object file, according to the target
 /// platform's object file format.

From 0a96176533ad5c0f8dc3b42c64bf907fb9c27f0b Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Thu, 24 Oct 2024 22:23:13 +1100
Subject: [PATCH 02/13] coverage: Make obtaining the codegen coverage context
 infallible

In all the situations where this context is needed, it should always be
available.
---
 compiler/rustc_codegen_llvm/src/context.rs    |  8 ++---
 .../src/coverageinfo/mapgen.rs                | 12 ++------
 .../src/coverageinfo/mod.rs                   | 29 +++++++------------
 3 files changed, 16 insertions(+), 33 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 2f830d6f941e7..7faa005abd29b 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -80,6 +80,7 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
 
     pub isize_ty: &'ll Type,
 
+    /// Extra codegen state needed when coverage instrumentation is enabled.
     pub coverage_cx: Option<coverageinfo::CrateCoverageContext<'ll, 'tcx>>,
     pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
 
@@ -592,11 +593,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         &self.statics_to_rauw
     }
 
+    /// Extra state that is only available when coverage instrumentation is enabled.
     #[inline]
-    pub(crate) fn coverage_context(
-        &self,
-    ) -> Option<&coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
-        self.coverage_cx.as_ref()
+    pub(crate) fn coverage_cx(&self) -> &coverageinfo::CrateCoverageContext<'ll, 'tcx> {
+        self.coverage_cx.as_ref().expect("only called when coverage instrumentation is enabled")
     }
 
     pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index b69ca62341340..7a2a802eb4eb0 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -54,11 +54,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         add_unused_functions(cx);
     }
 
-    let function_coverage_map = match cx.coverage_context() {
-        Some(ctx) => ctx.take_function_coverage_map(),
-        None => return,
-    };
-
+    let function_coverage_map = cx.coverage_cx().take_function_coverage_map();
     if function_coverage_map.is_empty() {
         // This module has no functions with coverage instrumentation
         return;
@@ -543,9 +539,5 @@ fn add_unused_function_coverage<'tcx>(
     // zero, because none of its counters/expressions are marked as seen.
     let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info);
 
-    if let Some(coverage_context) = cx.coverage_context() {
-        coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
-    } else {
-        bug!("Could not get the `coverage_context`");
-    }
+    cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage);
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 58607ce7497ff..eaf720cc769ec 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -7,7 +7,6 @@ use rustc_codegen_ssa::traits::{
 };
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_llvm::RustString;
-use rustc_middle::bug;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::layout::HasTyCtxt;
@@ -76,15 +75,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     /// `instrprof.increment()`. The `Value` is only created once per instance.
     /// Multiple invocations with the same instance return the same `Value`.
     fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
-        if let Some(coverage_context) = self.coverage_context() {
-            debug!("getting pgo_func_name_var for instance={:?}", instance);
-            let mut pgo_func_name_var_map = coverage_context.pgo_func_name_var_map.borrow_mut();
-            pgo_func_name_var_map
-                .entry(instance)
-                .or_insert_with(|| create_pgo_func_name_var(self, instance))
-        } else {
-            bug!("Could not get the `coverage_context`");
-        }
+        debug!("getting pgo_func_name_var for instance={:?}", instance);
+        let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
+        pgo_func_name_var_map
+            .entry(instance)
+            .or_insert_with(|| create_pgo_func_name_var(self, instance))
     }
 }
 
@@ -118,11 +113,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
             cond_bitmaps.push(cond_bitmap);
         }
 
-        self.coverage_context()
-            .expect("always present when coverage is enabled")
-            .mcdc_condition_bitmap_map
-            .borrow_mut()
-            .insert(instance, cond_bitmaps);
+        self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -143,8 +134,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
             return;
         };
 
-        let Some(coverage_context) = bx.coverage_context() else { return };
-        let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
+        let mut coverage_map = bx.coverage_cx().function_coverage_map.borrow_mut();
         let func_coverage = coverage_map
             .entry(instance)
             .or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));
@@ -186,7 +176,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
             }
             CoverageKind::CondBitmapUpdate { index, decision_depth } => {
                 drop(coverage_map);
-                let cond_bitmap = coverage_context
+                let cond_bitmap = bx
+                    .coverage_cx()
                     .try_get_mcdc_condition_bitmap(&instance, decision_depth)
                     .expect("mcdc cond bitmap should have been allocated for updating");
                 let cond_index = bx.const_i32(index as i32);
@@ -194,7 +185,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
             }
             CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
                 drop(coverage_map);
-                let cond_bitmap = coverage_context
+                let cond_bitmap = bx.coverage_cx()
                                     .try_get_mcdc_condition_bitmap(&instance, decision_depth)
                                     .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
                 assert!(

From 0356908cf5e5ead075608709663a38b51c584872 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Thu, 24 Oct 2024 22:05:42 +1100
Subject: [PATCH 03/13] coverage: Store `covfun_section_name` in the codegen
 context

Adding an extra `OnceCell` to `CrateCoverageContext` is much nicer than trying
to thread this string through multiple layers of function calls that already
have access to the context.
---
 .../src/coverageinfo/mapgen.rs                |  7 +--
 .../src/coverageinfo/mod.rs                   | 44 +++++++++----------
 2 files changed, 24 insertions(+), 27 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 7a2a802eb4eb0..5b39d078e0d7e 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,4 +1,4 @@
-use std::ffi::{CStr, CString};
+use std::ffi::CString;
 
 use itertools::Itertools as _;
 use rustc_abi::Align;
@@ -81,7 +81,6 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
     generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
 
     let mut unused_function_names = Vec::new();
-    let covfun_section_name = coverageinfo::covfun_section_name(cx);
 
     // Encode coverage mappings and generate function records
     for (instance, function_coverage) in function_coverage_entries {
@@ -112,7 +111,6 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
 
         generate_covfun_record(
             cx,
-            &covfun_section_name,
             mangled_function_name,
             source_hash,
             filenames_ref,
@@ -360,7 +358,6 @@ fn generate_covmap_record<'ll>(
 /// as a global variable in the `__llvm_covfun` section.
 fn generate_covfun_record(
     cx: &CodegenCx<'_, '_>,
-    covfun_section_name: &CStr,
     mangled_function_name: &str,
     source_hash: u64,
     filenames_ref: u64,
@@ -401,7 +398,7 @@ fn generate_covfun_record(
     llvm::set_global_constant(llglobal, true);
     llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
     llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
-    llvm::set_section(llglobal, covfun_section_name);
+    llvm::set_section(llglobal, cx.covfun_section_name());
     // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
     llvm::set_alignment(llglobal, Align::EIGHT);
     if cx.target_spec().supports_comdat() {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index eaf720cc769ec..e4f78dd877e9f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,5 +1,5 @@
-use std::cell::RefCell;
-use std::ffi::CString;
+use std::cell::{OnceCell, RefCell};
+use std::ffi::{CStr, CString};
 
 use libc::c_uint;
 use rustc_codegen_ssa::traits::{
@@ -29,6 +29,8 @@ pub(crate) struct CrateCoverageContext<'ll, 'tcx> {
         RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
     pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
     pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
+
+    covfun_section_name: OnceCell<CString>,
 }
 
 impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
@@ -37,6 +39,7 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
             function_coverage_map: Default::default(),
             pgo_func_name_var_map: Default::default(),
             mcdc_condition_bitmap_map: Default::default(),
+            covfun_section_name: Default::default(),
         }
     }
 
@@ -63,13 +66,28 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
     }
 }
 
-// These methods used to be part of trait `CoverageInfoMethods`, which no longer
-// exists after most coverage code was moved out of SSA.
 impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     pub(crate) fn coverageinfo_finalize(&self) {
         mapgen::finalize(self)
     }
 
+    /// Returns the section name to use when embedding per-function coverage information
+    /// in the object file, according to the target's object file format. LLVM's coverage
+    /// tools use information from this section when producing coverage reports.
+    ///
+    /// Typical values are:
+    /// - `__llvm_covfun` on Linux
+    /// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
+    /// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
+    fn covfun_section_name(&self) -> &CStr {
+        self.coverage_cx().covfun_section_name.get_or_init(|| {
+            CString::new(llvm::build_byte_buffer(|s| unsafe {
+                llvm::LLVMRustCoverageWriteFuncSectionNameToString(self.llmod, s);
+            }))
+            .expect("covfun section name should not contain NUL")
+        })
+    }
+
     /// For LLVM codegen, returns a function-specific `Value` for a global
     /// string, to hold the function name passed to LLVM intrinsic
     /// `instrprof.increment()`. The `Value` is only created once per instance.
@@ -278,21 +296,3 @@ pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
 pub(crate) fn mapping_version() -> u32 {
     unsafe { llvm::LLVMRustCoverageMappingVersion() }
 }
-
-/// Returns the section name string to pass through to the linker when embedding
-/// per-function coverage information in the object file, according to the target
-/// platform's object file format.
-///
-/// LLVM's coverage tools read coverage mapping details from this section when
-/// producing coverage reports.
-///
-/// Typical values are:
-/// - `__llvm_covfun` on Linux
-/// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
-/// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
-pub(crate) fn covfun_section_name(cx: &CodegenCx<'_, '_>) -> CString {
-    CString::new(llvm::build_byte_buffer(|s| unsafe {
-        llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
-    }))
-    .expect("covfun section name should not contain NUL")
-}

From e2d3f5aaec941850479e16e89ebfb70824e65a45 Mon Sep 17 00:00:00 2001
From: Manuel Drehwald <git@manuel.drehwald.info>
Date: Sat, 12 Oct 2024 00:16:39 +0200
Subject: [PATCH 04/13] Allow building rustc's LLVM with Offload support

---
 config.example.toml                        |  3 +++
 src/bootstrap/configure.py                 |  1 +
 src/bootstrap/src/core/build_steps/llvm.rs | 15 +++++++++++++++
 src/bootstrap/src/core/config/config.rs    |  9 +++++++++
 src/bootstrap/src/utils/change_tracker.rs  |  5 +++++
 5 files changed, 33 insertions(+)

diff --git a/config.example.toml b/config.example.toml
index a52968e9a414d..d5b904ebf3d59 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -84,6 +84,9 @@
 # Wheter to build Enzyme as AutoDiff backend.
 #enzyme = false
 
+# Whether to build LLVM with support for it's gpu offload runtime.
+#offload = false
+
 # Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in
 # PATH, or set an absolute path to use a specific version.
 #ccache = false
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 15137fbb2b5c2..2e173c9e6df48 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -72,6 +72,7 @@ def v(*args):
 o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
 o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
 o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme")
+o("llvm-offload", "llvm.offload", "build LLVM with gpu offload support")
 o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface")
 o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
 o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions")
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index a2d40f6fbd891..ffb7d9a9e0e74 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -472,6 +472,21 @@ impl Step for Llvm {
             cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";"));
         }
 
+        let mut enabled_llvm_runtimes = Vec::new();
+
+        if builder.config.llvm_offload {
+            enabled_llvm_runtimes.push("offload");
+            //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp.
+            //Remove this line once they achieved it.
+            enabled_llvm_runtimes.push("openmp");
+        }
+
+        if !enabled_llvm_runtimes.is_empty() {
+            enabled_llvm_runtimes.sort();
+            enabled_llvm_runtimes.dedup();
+            cfg.define("LLVM_ENABLE_RUNTIMES", enabled_llvm_runtimes.join(";"));
+        }
+
         if let Some(num_linkers) = builder.config.llvm_link_jobs {
             if num_linkers > 0 {
                 cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 444c97a2048e3..087dde0d9c6b2 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -224,6 +224,7 @@ pub struct Config {
     pub llvm_assertions: bool,
     pub llvm_tests: bool,
     pub llvm_enzyme: bool,
+    pub llvm_offload: bool,
     pub llvm_plugins: bool,
     pub llvm_optimize: bool,
     pub llvm_thin_lto: bool,
@@ -938,6 +939,7 @@ define_config! {
         use_libcxx: Option<bool> = "use-libcxx",
         use_linker: Option<String> = "use-linker",
         allow_old_toolchain: Option<bool> = "allow-old-toolchain",
+        offload: Option<bool> = "offload",
         polly: Option<bool> = "polly",
         clang: Option<bool> = "clang",
         enable_warnings: Option<bool> = "enable-warnings",
@@ -1647,6 +1649,7 @@ impl Config {
         // we'll infer default values for them later
         let mut llvm_tests = None;
         let mut llvm_enzyme = None;
+        let mut llvm_offload = None;
         let mut llvm_plugins = None;
         let mut debug = None;
         let mut debug_assertions = None;
@@ -1884,6 +1887,7 @@ impl Config {
                 use_libcxx,
                 use_linker,
                 allow_old_toolchain,
+                offload,
                 polly,
                 clang,
                 enable_warnings,
@@ -1900,6 +1904,7 @@ impl Config {
             set(&mut config.ninja_in_file, ninja);
             llvm_tests = tests;
             llvm_enzyme = enzyme;
+            llvm_offload = offload;
             llvm_plugins = plugins;
             set(&mut config.llvm_optimize, optimize_toml);
             set(&mut config.llvm_thin_lto, thin_lto);
@@ -1921,6 +1926,7 @@ impl Config {
             set(&mut config.llvm_use_libcxx, use_libcxx);
             config.llvm_use_linker.clone_from(&use_linker);
             config.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false);
+            config.llvm_offload = offload.unwrap_or(false);
             config.llvm_polly = polly.unwrap_or(false);
             config.llvm_clang = clang.unwrap_or(false);
             config.llvm_enable_warnings = enable_warnings.unwrap_or(false);
@@ -2097,6 +2103,7 @@ impl Config {
 
         config.llvm_tests = llvm_tests.unwrap_or(false);
         config.llvm_enzyme = llvm_enzyme.unwrap_or(false);
+        config.llvm_offload = llvm_offload.unwrap_or(false);
         config.llvm_plugins = llvm_plugins.unwrap_or(false);
         config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
 
@@ -2963,6 +2970,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm(
         use_libcxx,
         use_linker,
         allow_old_toolchain,
+        offload,
         polly,
         clang,
         enable_warnings,
@@ -2985,6 +2993,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm(
     err!(current_llvm_config.use_libcxx, use_libcxx);
     err!(current_llvm_config.use_linker, use_linker);
     err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain);
+    err!(current_llvm_config.offload, offload);
     err!(current_llvm_config.polly, polly);
     err!(current_llvm_config.clang, clang);
     err!(current_llvm_config.build_config, build_config);
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index fac24572a878c..b9cf8f0531698 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -285,4 +285,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "New option `build.compiletest-diff-tool` that adds support for a custom differ for compiletest",
     },
+    ChangeInfo {
+        change_id: 131513,
+        severity: ChangeSeverity::Info,
+        summary: "New option `llvm.offload` to control whether the llvm offload runtime for GPU support is built. Implicitly enables the openmp runtime as dependency.",
+    },
 ];

From aa14cb896b789a0e0b20dd44999888b75ed5f7bb Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Fri, 25 Oct 2024 18:22:03 +1100
Subject: [PATCH 05/13] Add a macro that derives `TryFrom<u32>` for fieldless
 enums

---
 compiler/rustc_macros/src/lib.rs             | 10 ++++
 compiler/rustc_macros/src/try_from.rs        | 53 ++++++++++++++++++++
 tests/ui-fulldeps/try-from-u32/errors.rs     | 24 +++++++++
 tests/ui-fulldeps/try-from-u32/errors.stderr | 32 ++++++++++++
 tests/ui-fulldeps/try-from-u32/hygiene.rs    | 32 ++++++++++++
 tests/ui-fulldeps/try-from-u32/values.rs     | 36 +++++++++++++
 6 files changed, 187 insertions(+)
 create mode 100644 compiler/rustc_macros/src/try_from.rs
 create mode 100644 tests/ui-fulldeps/try-from-u32/errors.rs
 create mode 100644 tests/ui-fulldeps/try-from-u32/errors.stderr
 create mode 100644 tests/ui-fulldeps/try-from-u32/hygiene.rs
 create mode 100644 tests/ui-fulldeps/try-from-u32/values.rs

diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index f46c795b9565c..0df674eb4c909 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -20,6 +20,7 @@ mod lift;
 mod query;
 mod serialize;
 mod symbols;
+mod try_from;
 mod type_foldable;
 mod type_visitable;
 
@@ -165,3 +166,12 @@ decl_derive!(
         suggestion_part,
         applicability)] => diagnostics::subdiagnostic_derive
 );
+
+decl_derive! {
+    [TryFromU32] =>
+    /// Derives `TryFrom<u32>` for the annotated `enum`, which must have no fields.
+    /// Each variant maps to the value it would produce under an `as u32` cast.
+    ///
+    /// The error type is `u32`.
+    try_from::try_from_u32
+}
diff --git a/compiler/rustc_macros/src/try_from.rs b/compiler/rustc_macros/src/try_from.rs
new file mode 100644
index 0000000000000..fde7c8f620400
--- /dev/null
+++ b/compiler/rustc_macros/src/try_from.rs
@@ -0,0 +1,53 @@
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned};
+use syn::Data;
+use syn::spanned::Spanned;
+use synstructure::Structure;
+
+pub(crate) fn try_from_u32(s: Structure<'_>) -> TokenStream {
+    let span_error = |span, message: &str| {
+        quote_spanned! { span => const _: () = ::core::compile_error!(#message); }
+    };
+
+    // Must be applied to an enum type.
+    if let Some(span) = match &s.ast().data {
+        Data::Enum(_) => None,
+        Data::Struct(s) => Some(s.struct_token.span()),
+        Data::Union(u) => Some(u.union_token.span()),
+    } {
+        return span_error(span, "type is not an enum (TryFromU32)");
+    }
+
+    // The enum's variants must not have fields.
+    let variant_field_errors = s
+        .variants()
+        .iter()
+        .filter_map(|v| v.ast().fields.iter().map(|f| f.span()).next())
+        .map(|span| span_error(span, "enum variant cannot have fields (TryFromU32)"))
+        .collect::<TokenStream>();
+    if !variant_field_errors.is_empty() {
+        return variant_field_errors;
+    }
+
+    let ctor = s
+        .variants()
+        .iter()
+        .map(|v| v.construct(|_, _| -> TokenStream { unreachable!() }))
+        .collect::<Vec<_>>();
+    s.gen_impl(quote! {
+        // The surrounding code might have shadowed these identifiers.
+        use ::core::convert::TryFrom;
+        use ::core::primitive::u32;
+        use ::core::result::Result::{self, Ok, Err};
+
+        gen impl TryFrom<u32> for @Self {
+            type Error = u32;
+
+            #[allow(deprecated)] // Don't warn about deprecated variants.
+            fn try_from(value: u32) -> Result<Self, Self::Error> {
+                #( if value == const { #ctor as u32 } { return Ok(#ctor) } )*
+                Err(value)
+            }
+        }
+    })
+}
diff --git a/tests/ui-fulldeps/try-from-u32/errors.rs b/tests/ui-fulldeps/try-from-u32/errors.rs
new file mode 100644
index 0000000000000..0470063312cb2
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.rs
@@ -0,0 +1,24 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+
+// Checks the error messages produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32)]
+struct MyStruct {} //~ type is not an enum
+
+#[derive(TryFromU32)]
+enum NonTrivial {
+    A,
+    B(),
+    C {},
+    D(bool),                //~ enum variant cannot have fields
+    E(bool, bool),          //~ enum variant cannot have fields
+    F { x: bool },          //~ enum variant cannot have fields
+    G { x: bool, y: bool }, //~ enum variant cannot have fields
+}
+
+fn main() {}
diff --git a/tests/ui-fulldeps/try-from-u32/errors.stderr b/tests/ui-fulldeps/try-from-u32/errors.stderr
new file mode 100644
index 0000000000000..d20567061d7bb
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.stderr
@@ -0,0 +1,32 @@
+error: type is not an enum (TryFromU32)
+  --> $DIR/errors.rs:11:1
+   |
+LL | struct MyStruct {}
+   | ^^^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:18:7
+   |
+LL |     D(bool),
+   |       ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:19:7
+   |
+LL |     E(bool, bool),
+   |       ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:20:9
+   |
+LL |     F { x: bool },
+   |         ^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:21:9
+   |
+LL |     G { x: bool, y: bool },
+   |         ^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui-fulldeps/try-from-u32/hygiene.rs b/tests/ui-fulldeps/try-from-u32/hygiene.rs
new file mode 100644
index 0000000000000..e0655a64a64db
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/hygiene.rs
@@ -0,0 +1,32 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ check-pass
+
+// Checks that the derive macro still works even if the surrounding code has
+// shadowed the relevant library types.
+
+extern crate rustc_macros;
+
+mod submod {
+    use rustc_macros::TryFromU32;
+
+    struct Result;
+    trait TryFrom {}
+    #[allow(non_camel_case_types)]
+    struct u32;
+    struct Ok;
+    struct Err;
+    mod core {}
+    mod std {}
+
+    #[derive(TryFromU32)]
+    pub(crate) enum MyEnum {
+        Zero,
+        One,
+    }
+}
+
+fn main() {
+    use submod::MyEnum;
+    let _: Result<MyEnum, u32> = MyEnum::try_from(1u32);
+}
diff --git a/tests/ui-fulldeps/try-from-u32/values.rs b/tests/ui-fulldeps/try-from-u32/values.rs
new file mode 100644
index 0000000000000..180a8f2beb75b
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/values.rs
@@ -0,0 +1,36 @@
+#![feature(assert_matches)]
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ run-pass
+
+// Checks the values accepted by the `TryFrom<u32>` impl produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use core::assert_matches::assert_matches;
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32, Debug, PartialEq)]
+#[repr(u32)]
+enum Repr {
+    Zero,
+    One(),
+    Seven = 7,
+}
+
+#[derive(TryFromU32, Debug)]
+enum NoRepr {
+    Zero,
+    One,
+}
+
+fn main() {
+    assert_eq!(Repr::try_from(0u32), Ok(Repr::Zero));
+    assert_eq!(Repr::try_from(1u32), Ok(Repr::One()));
+    assert_eq!(Repr::try_from(2u32), Err(2));
+    assert_eq!(Repr::try_from(7u32), Ok(Repr::Seven));
+
+    assert_matches!(NoRepr::try_from(0u32), Ok(NoRepr::Zero));
+    assert_matches!(NoRepr::try_from(1u32), Ok(NoRepr::One));
+    assert_matches!(NoRepr::try_from(2u32), Err(2));
+}

From ce87180e9f80f0f83c46295319b3dd66ddc06ed8 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Fri, 25 Oct 2024 21:40:38 +1100
Subject: [PATCH 06/13] Use safe wrappers `get_linkage` and `set_linkage`

---
 compiler/rustc_codegen_llvm/src/back/write.rs |  8 +-
 compiler/rustc_codegen_llvm/src/callee.rs     |  4 +-
 compiler/rustc_codegen_llvm/src/common.rs     |  2 +-
 compiler/rustc_codegen_llvm/src/consts.rs     | 80 +++++++++----------
 compiler/rustc_codegen_llvm/src/context.rs    |  2 +-
 .../rustc_codegen_llvm/src/debuginfo/gdb.rs   |  2 +-
 compiler/rustc_codegen_llvm/src/intrinsic.rs  | 13 ++-
 compiler/rustc_codegen_llvm/src/llvm/mod.rs   |  4 +
 compiler/rustc_codegen_llvm/src/mono_item.rs  |  6 +-
 9 files changed, 60 insertions(+), 61 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index afdd2b581b86e..bf77fc56d08c9 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -1043,7 +1043,7 @@ unsafe fn embed_bitcode(
 
             let section = bitcode_section_name(cgcx);
             llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
-            llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
             llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
 
             let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
@@ -1061,7 +1061,7 @@ unsafe fn embed_bitcode(
                 c".llvmcmd"
             };
             llvm::LLVMSetSection(llglobal, section.as_ptr());
-            llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
         } else {
             // We need custom section flags, so emit module-level inline assembly.
             let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
@@ -1096,7 +1096,7 @@ fn create_msvc_imps(
         let ptr_ty = Type::ptr_llcx(llcx);
         let globals = base::iter_globals(llmod)
             .filter(|&val| {
-                llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage
+                llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage
                     && llvm::LLVMIsDeclaration(val) == 0
             })
             .filter_map(|val| {
@@ -1115,7 +1115,7 @@ fn create_msvc_imps(
         for (imp_name, val) in globals {
             let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr());
             llvm::LLVMSetInitializer(imp, val);
-            llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
+            llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage);
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 206a706979204..5edc1c7138a24 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -95,9 +95,9 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
         // whether we are sharing generics or not. The important thing here is
         // that the visibility we apply to the declaration is the same one that
         // has been applied to the definition (wherever that definition may be).
-        unsafe {
-            llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
 
+        llvm::set_linkage(llfn, llvm::Linkage::ExternalLinkage);
+        unsafe {
             let is_generic =
                 instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
 
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 0ced37b53a841..ff47eb944dd4a 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -219,8 +219,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     llvm::LLVMSetInitializer(g, sc);
                     llvm::LLVMSetGlobalConstant(g, True);
                     llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
-                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
                 }
+                llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
                 (s.to_owned(), g)
             })
             .1;
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 33a85adeb8781..0bfd433418ac0 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -172,29 +172,27 @@ fn check_and_apply_linkage<'ll, 'tcx>(
     if let Some(linkage) = attrs.import_linkage {
         debug!("get_static: sym={} linkage={:?}", sym, linkage);
 
-        unsafe {
-            // Declare a symbol `foo` with the desired linkage.
-            let g1 = cx.declare_global(sym, cx.type_i8());
-            llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
-
-            // Declare an internal global `extern_with_linkage_foo` which
-            // is initialized with the address of `foo`. If `foo` is
-            // discarded during linking (for example, if `foo` has weak
-            // linkage and there are no definitions), then
-            // `extern_with_linkage_foo` will instead be initialized to
-            // zero.
-            let mut real_name = "_rust_extern_with_linkage_".to_string();
-            real_name.push_str(sym);
-            let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
-                cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
-                    span: cx.tcx.def_span(def_id),
-                    symbol_name: sym,
-                })
-            });
-            llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
-            llvm::LLVMSetInitializer(g2, g1);
-            g2
-        }
+        // Declare a symbol `foo` with the desired linkage.
+        let g1 = cx.declare_global(sym, cx.type_i8());
+        llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
+
+        // Declare an internal global `extern_with_linkage_foo` which
+        // is initialized with the address of `foo`. If `foo` is
+        // discarded during linking (for example, if `foo` has weak
+        // linkage and there are no definitions), then
+        // `extern_with_linkage_foo` will instead be initialized to
+        // zero.
+        let mut real_name = "_rust_extern_with_linkage_".to_string();
+        real_name.push_str(sym);
+        let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
+            cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
+                span: cx.tcx.def_span(def_id),
+                symbol_name: sym,
+            })
+        });
+        llvm::set_linkage(g2, llvm::Linkage::InternalLinkage);
+        unsafe { llvm::LLVMSetInitializer(g2, g1) };
+        g2
     } else if cx.tcx.sess.target.arch == "x86"
         && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
     {
@@ -224,23 +222,21 @@ impl<'ll> CodegenCx<'ll, '_> {
         align: Align,
         kind: Option<&str>,
     ) -> &'ll Value {
-        unsafe {
-            let gv = match kind {
-                Some(kind) if !self.tcx.sess.fewer_names() => {
-                    let name = self.generate_local_symbol_name(kind);
-                    let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
-                        bug!("symbol `{}` is already defined", name);
-                    });
-                    llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
-                    gv
-                }
-                _ => self.define_private_global(self.val_ty(cv)),
-            };
-            llvm::LLVMSetInitializer(gv, cv);
-            set_global_alignment(self, gv, align);
-            llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
-            gv
-        }
+        let gv = match kind {
+            Some(kind) if !self.tcx.sess.fewer_names() => {
+                let name = self.generate_local_symbol_name(kind);
+                let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
+                    bug!("symbol `{}` is already defined", name);
+                });
+                llvm::set_linkage(gv, llvm::Linkage::PrivateLinkage);
+                gv
+            }
+            _ => self.define_private_global(self.val_ty(cv)),
+        };
+        unsafe { llvm::LLVMSetInitializer(gv, cv) };
+        set_global_alignment(self, gv, align);
+        llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
+        gv
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -401,7 +397,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                 let name = llvm::get_value_name(g).to_vec();
                 llvm::set_value_name(g, b"");
 
-                let linkage = llvm::LLVMRustGetLinkage(g);
+                let linkage = llvm::get_linkage(g);
                 let visibility = llvm::LLVMRustGetVisibility(g);
 
                 let new_g = llvm::LLVMRustGetOrInsertGlobal(
@@ -411,7 +407,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                     val_llty,
                 );
 
-                llvm::LLVMRustSetLinkage(new_g, linkage);
+                llvm::set_linkage(new_g, linkage);
                 llvm::LLVMRustSetVisibility(new_g, visibility);
 
                 // The old global has had its name removed but is returned by
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index fb845c0087b1f..b5985a6aa1ea7 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -605,7 +605,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         unsafe {
             let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
             llvm::LLVMSetInitializer(g, array);
-            llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+            llvm::set_linkage(g, llvm::Linkage::AppendingLinkage);
             llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr());
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index f93d3e40b2051..7947c9c8c8efd 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -76,7 +76,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
             llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
             llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
-            llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
+            llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
             // This should make sure that the whole section is not larger than
             // the string it contains. Otherwise we get a warning from GDB.
             llvm::LLVMSetAlignment(section_var, 1);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c9a17c9852dbc..d04b525761942 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -785,13 +785,12 @@ fn codegen_msvc_try<'ll>(
         let type_info =
             bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false);
         let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
-        unsafe {
-            llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
-            if bx.cx.tcx.sess.target.supports_comdat() {
-                llvm::SetUniqueComdat(bx.llmod, tydesc);
-            }
-            llvm::LLVMSetInitializer(tydesc, type_info);
+
+        llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
+        if bx.cx.tcx.sess.target.supports_comdat() {
+            llvm::SetUniqueComdat(bx.llmod, tydesc);
         }
+        unsafe { llvm::LLVMSetInitializer(tydesc, type_info) };
 
         // The flag value of 8 indicates that we are catching the exception by
         // reference instead of by value. We can't use catch by value because
@@ -1064,7 +1063,7 @@ fn gen_fn<'ll, 'tcx>(
     cx.set_frame_pointer_type(llfn);
     cx.apply_target_cpu_attr(llfn);
     // FIXME(eddyb) find a nicer way to do this.
-    unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
+    llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage);
     let llbb = Builder::append_block(cx, llfn, "entry-block");
     let bx = Builder::build(cx, llbb);
     codegen(bx);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index e837022044ee0..9900742d592fb 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -232,6 +232,10 @@ pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
     }
 }
 
+pub fn get_linkage(llglobal: &Value) -> Linkage {
+    unsafe { LLVMRustGetLinkage(llglobal) }
+}
+
 pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
     unsafe {
         LLVMRustSetLinkage(llglobal, linkage);
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index bf6ef219873a5..cd41e60522886 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -39,8 +39,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
                 .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
         });
 
+        llvm::set_linkage(g, base::linkage_to_llvm(linkage));
         unsafe {
-            llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
             llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
             if self.should_assume_dso_local(g, false) {
                 llvm::LLVMRustSetDSOLocal(g, true);
@@ -61,7 +61,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
 
         let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
-        unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
+        llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
         base::set_link_section(lldecl, attrs);
         if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
@@ -107,7 +107,7 @@ impl CodegenCx<'_, '_> {
         llval: &llvm::Value,
         is_declaration: bool,
     ) -> bool {
-        let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) };
+        let linkage = llvm::get_linkage(llval);
         let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) };
 
         if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {

From 62ffe3d911386cc5ca9b4e70a2fe652b1f626159 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Sat, 19 Oct 2024 12:17:33 +1100
Subject: [PATCH 07/13] Use safe wrappers `get_visibility` and `set_visibility`

---
 compiler/rustc_codegen_llvm/src/allocator.rs | 17 ++++-------------
 compiler/rustc_codegen_llvm/src/callee.rs    |  2 +-
 compiler/rustc_codegen_llvm/src/consts.rs    | 10 ++++------
 compiler/rustc_codegen_llvm/src/llvm/mod.rs  |  4 ++++
 compiler/rustc_codegen_llvm/src/mono_item.rs | 20 +++++++-------------
 5 files changed, 20 insertions(+), 33 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 89f5305840b94..55ee6dcdf8784 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -77,20 +77,14 @@ pub(crate) unsafe fn codegen(
         // __rust_alloc_error_handler_should_panic
         let name = OomStrategy::SYMBOL;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        llvm::LLVMRustSetVisibility(
-            ll_g,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let val = tcx.sess.opts.unstable_opts.oom.should_panic();
         let llval = llvm::LLVMConstInt(i8, val as u64, False);
         llvm::LLVMSetInitializer(ll_g, llval);
 
         let name = NO_ALLOC_SHIM_IS_UNSTABLE;
         let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        llvm::LLVMRustSetVisibility(
-            ll_g,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let llval = llvm::LLVMConstInt(i8, 0, False);
         llvm::LLVMSetInitializer(ll_g, llval);
     }
@@ -134,10 +128,7 @@ fn create_wrapper_function(
             None
         };
 
-        llvm::LLVMRustSetVisibility(
-            llfn,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
 
         if tcx.sess.must_emit_unwind_tables() {
             let uwtable =
@@ -151,7 +142,7 @@ fn create_wrapper_function(
             // -> ! DIFlagNoReturn
             attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
         }
-        llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+        llvm::set_visibility(callee, llvm::Visibility::Hidden);
 
         let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr());
 
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 5edc1c7138a24..975b1f4dc2e12 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -136,7 +136,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
                         || !cx.tcx.is_reachable_non_generic(instance_def_id))
             };
             if is_hidden {
-                llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+                llvm::set_visibility(llfn, llvm::Visibility::Hidden);
             }
 
             // MinGW: For backward compatibility we rely on the linker to decide whether it
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 0bfd433418ac0..1e3abcfd1af44 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -288,9 +288,7 @@ impl<'ll> CodegenCx<'ll, '_> {
             let g = self.declare_global(sym, llty);
 
             if !self.tcx.is_reachable_non_generic(def_id) {
-                unsafe {
-                    llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
-                }
+                llvm::set_visibility(g, llvm::Visibility::Hidden);
             }
 
             g
@@ -308,7 +306,7 @@ impl<'ll> CodegenCx<'ll, '_> {
             llvm::set_thread_local_mode(g, self.tls_model);
         }
 
-        let dso_local = unsafe { self.should_assume_dso_local(g, true) };
+        let dso_local = self.should_assume_dso_local(g, true);
         if dso_local {
             unsafe {
                 llvm::LLVMRustSetDSOLocal(g, true);
@@ -398,7 +396,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                 llvm::set_value_name(g, b"");
 
                 let linkage = llvm::get_linkage(g);
-                let visibility = llvm::LLVMRustGetVisibility(g);
+                let visibility = llvm::get_visibility(g);
 
                 let new_g = llvm::LLVMRustGetOrInsertGlobal(
                     self.llmod,
@@ -408,7 +406,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                 );
 
                 llvm::set_linkage(new_g, linkage);
-                llvm::LLVMRustSetVisibility(new_g, visibility);
+                llvm::set_visibility(new_g, visibility);
 
                 // The old global has had its name removed but is returned by
                 // get_static since it is in the instance cache. Provide an
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 9900742d592fb..235b5794b8c54 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -242,6 +242,10 @@ pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
     }
 }
 
+pub fn get_visibility(llglobal: &Value) -> Visibility {
+    unsafe { LLVMRustGetVisibility(llglobal) }
+}
+
 pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
     unsafe {
         LLVMRustSetVisibility(llglobal, visibility);
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index cd41e60522886..ea8857b4739c1 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -40,8 +40,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
         });
 
         llvm::set_linkage(g, base::linkage_to_llvm(linkage));
+        llvm::set_visibility(g, base::visibility_to_llvm(visibility));
         unsafe {
-            llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
             if self.should_assume_dso_local(g, false) {
                 llvm::LLVMRustSetDSOLocal(g, true);
             }
@@ -78,21 +78,15 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
             && linkage != Linkage::Private
             && self.tcx.is_compiler_builtins(LOCAL_CRATE)
         {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
-            }
+            llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
         } else {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility));
-            }
+            llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
         }
 
         debug!("predefine_fn: instance = {:?}", instance);
 
-        unsafe {
-            if self.should_assume_dso_local(lldecl, false) {
-                llvm::LLVMRustSetDSOLocal(lldecl, true);
-            }
+        if self.should_assume_dso_local(lldecl, false) {
+            unsafe { llvm::LLVMRustSetDSOLocal(lldecl, true) };
         }
 
         self.instances.borrow_mut().insert(instance, lldecl);
@@ -102,13 +96,13 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
 impl CodegenCx<'_, '_> {
     /// Whether a definition or declaration can be assumed to be local to a group of
     /// libraries that form a single DSO or executable.
-    pub(crate) unsafe fn should_assume_dso_local(
+    pub(crate) fn should_assume_dso_local(
         &self,
         llval: &llvm::Value,
         is_declaration: bool,
     ) -> bool {
         let linkage = llvm::get_linkage(llval);
-        let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) };
+        let visibility = llvm::get_visibility(llval);
 
         if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
             return true;

From f2f67232a53b79b44c5b87fe5757ef1f18f4b590 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Sat, 26 Oct 2024 11:35:16 +0800
Subject: [PATCH 08/13] Deny calls to non-`#[const_trait]` methods in MIR
 constck

---
 .../src/check_consts/check.rs                 | 29 ++++++---
 .../unify-op-with-fn-call.stderr              | 30 ++++++---
 tests/ui/const-generics/issue-93647.stderr    |  4 --
 .../const-generics/issues/issue-90318.stderr  |  8 ---
 tests/ui/consts/closure-in-foreign-crate.rs   |  6 +-
 tests/ui/consts/const-fn-error.stderr         |  8 ---
 tests/ui/consts/const-for-feature-gate.stderr |  8 ---
 tests/ui/consts/const-for.stderr              |  8 ---
 tests/ui/consts/const-try-feature-gate.stderr |  8 ---
 tests/ui/consts/const-try.rs                  |  2 +
 tests/ui/consts/const-try.stderr              | 19 +++++-
 tests/ui/consts/const_cmp_type_id.rs          |  7 ++-
 tests/ui/consts/const_cmp_type_id.stderr      | 34 ++++++++++
 tests/ui/consts/control-flow/loop.stderr      | 16 -----
 tests/ui/consts/control-flow/try.stderr       |  8 ---
 tests/ui/consts/fn_trait_refs.stderr          | 20 ------
 .../invalid-inline-const-in-match-arm.stderr  |  4 --
 tests/ui/consts/issue-28113.stderr            |  4 --
 tests/ui/consts/issue-56164.stderr            |  4 --
 .../issue-68542-closure-in-array-len.stderr   |  4 --
 .../ui/consts/issue-73976-monomorphic.stderr  |  4 --
 tests/ui/consts/issue-90870.rs                |  3 -
 tests/ui/consts/issue-90870.stderr            | 18 +-----
 tests/ui/consts/issue-94675.stderr            |  4 --
 tests/ui/consts/try-operator.stderr           | 16 -----
 .../unstable-const-fn-in-libcore.stderr       |  4 --
 .../impl-trait/normalize-tait-in-const.stderr |  4 --
 tests/ui/issues/issue-25901.stderr            |  4 --
 tests/ui/never_type/issue-52443.stderr        |  8 ---
 .../issue-35813-postfix-after-cast.stderr     |  4 --
 tests/ui/resolve/issue-39559-2.stderr         |  8 ---
 ...bitrary-self-from-method-substs-ice.stderr |  4 --
 .../statics/check-values-constraints.stderr   |  4 --
 .../call-const-trait-method-pass.stderr       |  8 ---
 .../const-traits/call-generic-in-impl.stderr  |  4 --
 .../call-generic-method-chain.stderr          | 23 ++++++-
 .../call-generic-method-dup-bound.stderr      | 35 ++++++++++-
 .../const-traits/call-generic-method-fail.rs  |  4 +-
 .../call-generic-method-fail.stderr           | 15 +++++
 .../call-generic-method-pass.stderr           | 23 ++++++-
 tests/ui/traits/const-traits/call.rs          |  3 +-
 tests/ui/traits/const-traits/call.stderr      | 12 ++++
 .../const-closure-trait-method-fail.stderr    |  4 --
 .../const-closure-trait-method.stderr         |  4 --
 .../traits/const-traits/const-closures.stderr | 12 ----
 .../derive-const-non-const-type.stderr        | 14 ++++-
 .../const_derives/derive-const-use.stderr     | 62 +++++++++++++++----
 .../derive-const-with-params.stderr           | 22 ++++++-
 ...nst_closure-const_trait_impl-ice-113381.rs |  5 +-
 ...closure-const_trait_impl-ice-113381.stderr | 11 ++++
 .../ice-112822-expected-type-for-param.rs     |  1 +
 .../ice-112822-expected-type-for-param.stderr | 11 +++-
 .../traits/const-traits/generic-bound.stderr  |  4 --
 .../ui/traits/const-traits/hir-const-check.rs |  2 +
 .../const-traits/hir-const-check.stderr       | 25 +++++++-
 .../ice-126148-failed-to-normalize.rs         |  2 +
 .../ice-126148-failed-to-normalize.stderr     | 21 ++++++-
 .../inline-incorrect-early-bound-in-ctfe.rs   |  1 +
 ...nline-incorrect-early-bound-in-ctfe.stderr | 13 +++-
 .../traits/const-traits/issue-102985.stderr   |  4 --
 .../ui/traits/const-traits/issue-88155.stderr |  4 --
 .../match-non-const-eq.gated.stderr           |  4 --
 .../match-non-const-eq.stock.stderr           |  4 --
 ...st-op-const-closure-non-const-outer.stderr |  4 --
 .../non-const-op-in-closure-in-const.stderr   |  4 --
 .../const-traits/std-impl-gate.gated.stderr   |  4 --
 .../const-traits/std-impl-gate.stock.stderr   |  4 --
 .../super-traits-fail-2.nn.stderr             | 11 +++-
 .../super-traits-fail-2.ny.stderr             | 11 +++-
 .../const-traits/super-traits-fail-2.rs       |  1 +
 .../super-traits-fail-3.nn.stderr             | 11 +++-
 .../super-traits-fail-3.ny.stderr             | 11 +++-
 .../const-traits/super-traits-fail-3.rs       |  1 +
 .../trait-default-body-stability.stderr       | 19 +++++-
 .../typeck_type_placeholder_item.stderr       |  8 ---
 75 files changed, 438 insertions(+), 324 deletions(-)
 create mode 100644 tests/ui/consts/const_cmp_type_id.stderr
 create mode 100644 tests/ui/traits/const-traits/call-generic-method-fail.stderr
 create mode 100644 tests/ui/traits/const-traits/call.stderr
 create mode 100644 tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr

diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 8f1a887a96144..004fb12419f11 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -616,14 +616,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                 let mut is_trait = false;
                 // Attempting to call a trait method?
-                if tcx.trait_of_item(callee).is_some() {
+                if let Some(trait_did) = tcx.trait_of_item(callee) {
                     trace!("attempting to call a trait method");
+
+                    let trait_is_const = tcx.is_const_trait(trait_did);
                     // trait method calls are only permitted when `effects` is enabled.
-                    // we don't error, since that is handled by typeck. We try to resolve
-                    // the trait into the concrete method, and uses that for const stability
-                    // checks.
+                    // typeck ensures the conditions for calling a const trait method are met,
+                    // so we only error if the trait isn't const. We try to resolve the trait
+                    // into the concrete method, and uses that for const stability checks.
                     // FIXME(effects) we might consider moving const stability checks to typeck as well.
-                    if tcx.features().effects() {
+                    if tcx.features().effects() && trait_is_const {
                         // This skips the check below that ensures we only call `const fn`.
                         is_trait = true;
 
@@ -638,17 +640,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             callee = def;
                         }
                     } else {
+                        // if the trait is const but the user has not enabled the feature(s),
+                        // suggest them.
+                        let feature = if trait_is_const {
+                            Some(if tcx.features().const_trait_impl() {
+                                sym::effects
+                            } else {
+                                sym::const_trait_impl
+                            })
+                        } else {
+                            None
+                        };
                         self.check_op(ops::FnCallNonConst {
                             caller,
                             callee,
                             args: fn_args,
                             span: *fn_span,
                             call_source,
-                            feature: Some(if tcx.features().const_trait_impl() {
-                                sym::effects
-                            } else {
-                                sym::const_trait_impl
-                            }),
+                            feature,
                         });
                         // If we allowed this, we're in miri-unleashed mode, so we might
                         // as well skip the remaining checks.
diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
index bae8249845c02..b8d7c94bddc80 100644
--- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
@@ -27,11 +27,13 @@ LL + #[derive(ConstParamTy)]
 LL | struct Foo(u8);
    |
 
-error[E0284]: type annotations needed: cannot normalize `foo<N>::{constant#0}`
-  --> $DIR/unify-op-with-fn-call.rs:20:25
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/unify-op-with-fn-call.rs:20:39
    |
 LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
-   |                         ^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo<N>::{constant#0}`
+   |                                       ^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
   --> $DIR/unify-op-with-fn-call.rs:20:17
@@ -63,11 +65,21 @@ error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
 LL | fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
    |                            ^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
 
-error[E0284]: type annotations needed: cannot normalize `foo<N>::{constant#0}`
-  --> $DIR/unify-op-with-fn-call.rs:21:11
+error[E0015]: cannot call non-const fn `<Foo as Add>::add` in constants
+  --> $DIR/unify-op-with-fn-call.rs:21:13
    |
 LL |     bar::<{ std::ops::Add::add(N, N) }>();
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo<N>::{constant#0}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<usize as Add>::add` in constants
+  --> $DIR/unify-op-with-fn-call.rs:30:14
+   |
+LL |     bar2::<{ std::ops::Add::add(N, N) }>();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
   --> $DIR/unify-op-with-fn-call.rs:30:12
@@ -75,7 +87,7 @@ error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
 LL |     bar2::<{ std::ops::Add::add(N, N) }>();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0284, E0741.
-For more information about an error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0015, E0284, E0741.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/const-generics/issue-93647.stderr b/tests/ui/const-generics/issue-93647.stderr
index 81f50a1b51724..38fb3d79459fb 100644
--- a/tests/ui/const-generics/issue-93647.stderr
+++ b/tests/ui/const-generics/issue-93647.stderr
@@ -6,10 +6,6 @@ LL |     (||1usize)()
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr
index a534e8f8d44f8..9c7cb5ceb58c0 100644
--- a/tests/ui/const-generics/issues/issue-90318.stderr
+++ b/tests/ui/const-generics/issues/issue-90318.stderr
@@ -29,10 +29,6 @@ LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const operator in constants
   --> $DIR/issue-90318.rs:22:10
@@ -43,10 +39,6 @@ LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs
index 701cf0910450d..94e40fcf1e418 100644
--- a/tests/ui/consts/closure-in-foreign-crate.rs
+++ b/tests/ui/consts/closure-in-foreign-crate.rs
@@ -1,8 +1,8 @@
-//@ aux-build:closure-in-foreign-crate.rs
+// FIXME(effects) aux-build:closure-in-foreign-crate.rs
 //@ build-pass
 
-extern crate closure_in_foreign_crate;
+// FIXME(effects) extern crate closure_in_foreign_crate;
 
-const _: () = closure_in_foreign_crate::test();
+// FIXME(effects) const _: () = closure_in_foreign_crate::test();
 
 fn main() {}
diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr
index e886a0b4fe44c..42a6f2704c9e7 100644
--- a/tests/ui/consts/const-fn-error.stderr
+++ b/tests/ui/consts/const-fn-error.stderr
@@ -22,10 +22,6 @@ LL |     for i in 0..x {
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions
   --> $DIR/const-fn-error.rs:5:14
@@ -34,10 +30,6 @@ LL |     for i in 0..x {
    |              ^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-for-feature-gate.stderr b/tests/ui/consts/const-for-feature-gate.stderr
index 3344611a60ca8..6e099a3159d9d 100644
--- a/tests/ui/consts/const-for-feature-gate.stderr
+++ b/tests/ui/consts/const-for-feature-gate.stderr
@@ -17,10 +17,6 @@ LL |     for _ in 0..5 {}
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/const-for-feature-gate.rs:4:14
@@ -29,10 +25,6 @@ LL |     for _ in 0..5 {}
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr
index 2b817c2d20c8e..78336dc93e857 100644
--- a/tests/ui/consts/const-for.stderr
+++ b/tests/ui/consts/const-for.stderr
@@ -7,10 +7,6 @@ LL |     for _ in 0..5 {}
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/const-for.rs:4:14
@@ -19,10 +15,6 @@ LL |     for _ in 0..5 {}
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr
index 0c4c16fc56ac0..dc1dabc2f4f65 100644
--- a/tests/ui/consts/const-try-feature-gate.stderr
+++ b/tests/ui/consts/const-try-feature-gate.stderr
@@ -17,10 +17,6 @@ LL |     Some(())?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
   --> $DIR/const-try-feature-gate.rs:4:5
@@ -31,10 +27,6 @@ LL |     Some(())?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs
index 2862b6ffb17bf..758c4dd1e8c41 100644
--- a/tests/ui/consts/const-try.rs
+++ b/tests/ui/consts/const-try.rs
@@ -34,6 +34,8 @@ impl const Try for TryMe {
 
 const fn t() -> TryMe {
     TryMe?;
+    //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions
+    //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions
     TryMe
 }
 
diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr
index ba9da2421073f..abb1a921cfa46 100644
--- a/tests/ui/consts/const-try.stderr
+++ b/tests/ui/consts/const-try.stderr
@@ -16,5 +16,22 @@ LL | impl const Try for TryMe {
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error: aborting due to 2 previous errors
+error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions
+  --> $DIR/const-try.rs:36:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions
+  --> $DIR/const-try.rs:36:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs
index 77482007be48a..3a54764f422f7 100644
--- a/tests/ui/consts/const_cmp_type_id.rs
+++ b/tests/ui/consts/const_cmp_type_id.rs
@@ -1,4 +1,3 @@
-//@ check-pass
 //@ compile-flags: -Znext-solver
 #![feature(const_type_id, const_trait_impl, effects)]
 #![allow(incomplete_features)]
@@ -7,11 +6,13 @@ use std::any::TypeId;
 
 fn main() {
     const {
-        // FIXME(effects) this isn't supposed to pass (right now) but it did.
-        // revisit binops typeck please.
         assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
+        //~^ ERROR cannot call non-const operator in constants
         assert!(TypeId::of::<()>() != TypeId::of::<u8>());
+        //~^ ERROR cannot call non-const operator in constants
         let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
+        //~^ ERROR cannot call non-const operator in constants
         // can't assert `_a` because it is not deterministic
+        // FIXME(effects) make it pass
     }
 }
diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr
new file mode 100644
index 0000000000000..12f35361b808a
--- /dev/null
+++ b/tests/ui/consts/const_cmp_type_id.stderr
@@ -0,0 +1,34 @@
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/const_cmp_type_id.rs:9:17
+   |
+LL |         assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/const_cmp_type_id.rs:11:17
+   |
+LL |         assert!(TypeId::of::<()>() != TypeId::of::<u8>());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/const_cmp_type_id.rs:13:18
+   |
+LL |         let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr
index 13d5d3e0b55c8..5e43c70e9dfbe 100644
--- a/tests/ui/consts/control-flow/loop.stderr
+++ b/tests/ui/consts/control-flow/loop.stderr
@@ -35,10 +35,6 @@ LL |     for i in 0..4 {
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/loop.rs:53:14
@@ -47,10 +43,6 @@ LL |     for i in 0..4 {
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot convert `std::ops::Range<i32>` into an iterator in constants
   --> $DIR/loop.rs:59:14
@@ -61,10 +53,6 @@ LL |     for i in 0..4 {
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/loop.rs:59:14
@@ -73,10 +61,6 @@ LL |     for i in 0..4 {
    |              ^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/consts/control-flow/try.stderr b/tests/ui/consts/control-flow/try.stderr
index e08f52369faaa..5e2c77318e782 100644
--- a/tests/ui/consts/control-flow/try.stderr
+++ b/tests/ui/consts/control-flow/try.stderr
@@ -17,10 +17,6 @@ LL |     x?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Option<i32>` in constant functions
   --> $DIR/try.rs:6:5
@@ -31,10 +27,6 @@ LL |     x?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index 2b012432afd41..82b2b87c4a5ad 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -183,10 +183,6 @@ LL |         assert!(test_one == (1, 1, 1));
    |                 ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const operator in constants
   --> $DIR/fn_trait_refs.rs:73:17
@@ -195,10 +191,6 @@ LL |         assert!(test_two == (2, 2));
    |                 ^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/fn_trait_refs.rs:15:5
@@ -211,10 +203,6 @@ help: consider further restricting this bound
    |
 LL |     T: ~const Fn<()> + ~const Destruct + ~const Fn(),
    |                                        +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/fn_trait_refs.rs:11:23
@@ -236,10 +224,6 @@ help: consider further restricting this bound
    |
 LL |     T: ~const FnMut<()> + ~const Destruct + ~const FnMut(),
    |                                           ++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/fn_trait_refs.rs:18:27
@@ -261,10 +245,6 @@ help: consider further restricting this bound
    |
 LL |     T: ~const FnOnce<()> + ~const FnOnce(),
    |                          +++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/fn_trait_refs.rs:32:21
diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
index 0e41053a29df0..2e48837bdcdcb 100644
--- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
+++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
@@ -6,10 +6,6 @@ LL |         const { (|| {})() } => {}
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: could not evaluate constant pattern
   --> $DIR/invalid-inline-const-in-match-arm.rs:5:9
diff --git a/tests/ui/consts/issue-28113.stderr b/tests/ui/consts/issue-28113.stderr
index c2f53870173a3..401536c1353ea 100644
--- a/tests/ui/consts/issue-28113.stderr
+++ b/tests/ui/consts/issue-28113.stderr
@@ -6,10 +6,6 @@ LL |     || -> u8 { 5 }()
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr
index 6ec4ce0fbd70e..de5a53c9ad264 100644
--- a/tests/ui/consts/issue-56164.stderr
+++ b/tests/ui/consts/issue-56164.stderr
@@ -6,10 +6,6 @@ LL | const fn foo() { (||{})() }
    |
    = note: closures need an RFC before allowed to be called in constant functions
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: function pointer calls are not allowed in constant functions
   --> $DIR/issue-56164.rs:5:5
diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.stderr b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
index b414a6e0dba0e..9f323b2259f8f 100644
--- a/tests/ui/consts/issue-68542-closure-in-array-len.stderr
+++ b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
@@ -6,10 +6,6 @@ LL |     a: [(); (|| { 0 })()]
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr
index 79dbed4bea82f..ef754b23ff06e 100644
--- a/tests/ui/consts/issue-73976-monomorphic.stderr
+++ b/tests/ui/consts/issue-73976-monomorphic.stderr
@@ -7,10 +7,6 @@ LL |     GetTypeId::<T>::VALUE == GetTypeId::<usize>::VALUE
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/any.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs
index e1929c68c70a1..b62769a33f8e2 100644
--- a/tests/ui/consts/issue-90870.rs
+++ b/tests/ui/consts/issue-90870.rs
@@ -3,9 +3,6 @@
 #![allow(dead_code)]
 
 const fn f(a: &u8, b: &u8) -> bool {
-//~^ HELP: add `#![feature(const_trait_impl)]`
-//~| HELP: add `#![feature(const_trait_impl)]`
-//~| HELP: add `#![feature(const_trait_impl)]`
     a == b
     //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr
index df88a0c95cc5b..ea987920d7d33 100644
--- a/tests/ui/consts/issue-90870.stderr
+++ b/tests/ui/consts/issue-90870.stderr
@@ -1,5 +1,5 @@
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:9:5
+  --> $DIR/issue-90870.rs:6:5
    |
 LL |     a == b
    |     ^^^^^^
@@ -9,13 +9,9 @@ help: consider dereferencing here
    |
 LL |     *a == *b
    |     +     +
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:15:5
+  --> $DIR/issue-90870.rs:12:5
    |
 LL |     a == b
    |     ^^^^^^
@@ -25,13 +21,9 @@ help: consider dereferencing here
    |
 LL |     ****a == ****b
    |     ++++     ++++
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/issue-90870.rs:22:12
+  --> $DIR/issue-90870.rs:19:12
    |
 LL |         if l == r {
    |            ^^^^^^
@@ -41,10 +33,6 @@ help: consider dereferencing here
    |
 LL |         if *l == *r {
    |            +     +
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr
index a85c5e10374f8..8cad13724f20e 100644
--- a/tests/ui/consts/issue-94675.stderr
+++ b/tests/ui/consts/issue-94675.stderr
@@ -7,10 +7,6 @@ LL |         self.bar[0] = baz.len();
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/try-operator.stderr b/tests/ui/consts/try-operator.stderr
index 2c8b4c7fcd9cb..40d96ed3a1005 100644
--- a/tests/ui/consts/try-operator.stderr
+++ b/tests/ui/consts/try-operator.stderr
@@ -13,10 +13,6 @@ LL |         Err(())?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/result.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Result<bool, ()>` in constant functions
   --> $DIR/try-operator.rs:10:9
@@ -27,10 +23,6 @@ LL |         Err(())?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/result.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions
   --> $DIR/try-operator.rs:18:9
@@ -41,10 +33,6 @@ LL |         None?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
   --> $DIR/try-operator.rs:18:9
@@ -55,10 +43,6 @@ LL |         None?;
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/option.rs:LL:COL
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index 59476f9860321..e546694070dd9 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -23,10 +23,6 @@ help: consider further restricting this bound
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T + ~const FnOnce()>(self, f: F) -> T {
    |                                                     +++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:19:60
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index f1e6207ed817d..b370a5d7eb116 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -37,10 +37,6 @@ help: consider further restricting this bound
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) {
    |                                                                              ++++++++++++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0493]: destructor of `F` cannot be evaluated at compile-time
   --> $DIR/normalize-tait-in-const.rs:26:79
diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr
index 3fedfd9641702..bcbc805908ffd 100644
--- a/tests/ui/issues/issue-25901.stderr
+++ b/tests/ui/issues/issue-25901.stderr
@@ -17,10 +17,6 @@ LL | impl Deref for A {
    | ^^^^^^^^^^^^^^^^
    = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr
index adcff6637b0d9..2207ceb503367 100644
--- a/tests/ui/never_type/issue-52443.stderr
+++ b/tests/ui/never_type/issue-52443.stderr
@@ -50,10 +50,6 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
 note: impl defined here, but it is not `const`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
   --> $DIR/issue-52443.rs:9:21
@@ -62,10 +58,6 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
index 66b57c772d546..e34371be3d262 100644
--- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
+++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
@@ -353,10 +353,6 @@ LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]);
    |
    = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 40 previous errors
 
diff --git a/tests/ui/resolve/issue-39559-2.stderr b/tests/ui/resolve/issue-39559-2.stderr
index 7f51357a56f44..ea27e7bd2508f 100644
--- a/tests/ui/resolve/issue-39559-2.stderr
+++ b/tests/ui/resolve/issue-39559-2.stderr
@@ -5,10 +5,6 @@ LL |     let array: [usize; Dim3::dim()]
    |                        ^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
   --> $DIR/issue-39559-2.rs:16:15
@@ -17,10 +13,6 @@ LL |         = [0; Dim3::dim()];
    |               ^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index 505b0a173fada..6ae60e7af47d8 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -5,10 +5,6 @@ LL |         self.0
    |         ^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0493]: destructor of `R` cannot be evaluated at compile-time
   --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43
diff --git a/tests/ui/statics/check-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr
index 24763c175fc89..b4ee34530d3bd 100644
--- a/tests/ui/statics/check-values-constraints.stderr
+++ b/tests/ui/statics/check-values-constraints.stderr
@@ -37,10 +37,6 @@ LL |     field2: SafeEnum::Variant4("str".to_string()),
    |
    = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-values-constraints.rs:96:5
diff --git a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
index c1cead542163e..32f53137a00e6 100644
--- a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
@@ -23,10 +23,6 @@ LL | const ADD_INT: Int = Int(1i32) + Int(2i32);
    |                      ^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions
   --> $DIR/call-const-trait-method-pass.rs:11:20
@@ -47,10 +43,6 @@ LL |         !self.eq(other)
    |               ^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions
   --> $DIR/call-const-trait-method-pass.rs:36:7
diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
index 368c22675e7f6..971e77e372b81 100644
--- a/tests/ui/traits/const-traits/call-generic-in-impl.stderr
+++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
@@ -19,10 +19,6 @@ LL |         PartialEq::eq(self, other)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
index 62eed0f14f9cb..aa90305c64826 100644
--- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
@@ -44,5 +44,26 @@ LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 5 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-chain.rs:21:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                          ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+  --> $DIR/call-generic-method-chain.rs:16:15
+   |
+LL |         !self.eq(other)
+   |               ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
index 3f9dce919d05f..029915b7646d8 100644
--- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
@@ -44,5 +44,38 @@ LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 5 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-dup-bound.rs:21:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self<T: PartialEq + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                                      ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+  --> $DIR/call-generic-method-dup-bound.rs:14:15
+   |
+LL |         !self.eq(other)
+   |               ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-dup-bound.rs:28:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self2<T: A + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                               ++++++++++++++++++++++++++++
+
+error: aborting due to 8 previous errors; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.rs b/tests/ui/traits/const-traits/call-generic-method-fail.rs
index 86e0eae61c9ce..6bfbbef6f762e 100644
--- a/tests/ui/traits/const-traits/call-generic-method-fail.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.rs
@@ -1,12 +1,10 @@
-//@ check-pass
 //@ compile-flags: -Znext-solver
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, effects)]
 
 pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
     *t == *t
-    // FIXME(effects) ~^ ERROR mismatched types
-    // FIXME(effects): diagnostic
+    //~^ ERROR cannot call non-const operator in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
new file mode 100644
index 0000000000000..5cd4216dce11e
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
@@ -0,0 +1,15 @@
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-fail.rs:6:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                       ++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
index e35de48ed6062..97ce7fe1c2a8a 100644
--- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
@@ -30,5 +30,26 @@ LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-pass.rs:21:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                          ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+  --> $DIR/call-generic-method-pass.rs:16:15
+   |
+LL |         !self.eq(other)
+   |               ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 5 previous errors; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs
index af2f7caf88c75..f96fb614ac2f9 100644
--- a/tests/ui/traits/const-traits/call.rs
+++ b/tests/ui/traits/const-traits/call.rs
@@ -1,10 +1,11 @@
-//@ check-pass
+// FIXME(effects) check-pass
 //@ compile-flags: -Znext-solver
 #![feature(const_closures, const_trait_impl, effects)]
 #![allow(incomplete_features)]
 
 pub const _: () = {
     assert!((const || true)());
+    //~^ ERROR cannot call non-const closure in constants
 };
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr
new file mode 100644
index 0000000000000..e9bf64092f3b7
--- /dev/null
+++ b/tests/ui/traits/const-traits/call.stderr
@@ -0,0 +1,12 @@
+error[E0015]: cannot call non-const closure in constants
+  --> $DIR/call.rs:7:13
+   |
+LL |     assert!((const || true)());
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constants
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
index 4e6707bba51ce..f0f033bceef44 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
@@ -23,10 +23,6 @@ help: consider further restricting this bound
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
    |                                                         +++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
index 0f0cd73cc102c..4c5a4d0cdf41b 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
@@ -23,10 +23,6 @@ help: consider further restricting this bound
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
    |                                                         +++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr
index 4d354cb281fea..a81804a50dc21 100644
--- a/tests/ui/traits/const-traits/const-closures.stderr
+++ b/tests/ui/traits/const-traits/const-closures.stderr
@@ -65,10 +65,6 @@ help: consider further restricting this bound
    |
 LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
    |                                      +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/const-closures.rs:24:11
@@ -81,10 +77,6 @@ help: consider further restricting this bound
    |
 LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
    |                                      +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/const-closures.rs:12:5
@@ -97,10 +89,6 @@ help: consider further restricting this bound
    |
 LL |         F: ~const FnOnce() -> u8 + ~const Fn(),
    |                                  +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 11 previous errors
 
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
index 777b3313da6b2..4bcc17952e620 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
@@ -22,5 +22,17 @@ LL | #[derive_const(Default)]
    = note: adding a non-const method body in the future would be a breaking change
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+  --> $DIR/derive-const-non-const-type.rs:11:14
+   |
+LL | #[derive_const(Default)]
+   |                ------- in this derive macro expansion
+LL | pub struct S(A);
+   |              ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
index ad727fc36cd76..d471a8253ba53 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
@@ -62,29 +62,67 @@ LL | #[derive_const(Default, PartialEq)]
    = note: adding a non-const method body in the future would be a breaking change
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0080]: evaluation of constant value failed
+error[E0015]: cannot call non-const fn `<S as Default>::default` in constants
+  --> $DIR/derive-const-use.rs:18:35
+   |
+LL | const _: () = assert!(S((), A) == S::default());
+   |                                   ^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+  --> $DIR/derive-const-use.rs:18:23
+   |
+LL | const _: () = assert!(S((), A) == S::default());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<() as Default>::default` in constant functions
   --> $DIR/derive-const-use.rs:16:14
    |
 LL | #[derive_const(Default, PartialEq)]
    |                ------- in this derive macro expansion
 LL | pub struct S((), A);
-   |              ^^ calling non-const function `<() as Default>::default`
+   |              ^^
    |
-note: inside `<S as Default>::default`
-  --> $DIR/derive-const-use.rs:16:14
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+  --> $DIR/derive-const-use.rs:16:18
    |
 LL | #[derive_const(Default, PartialEq)]
    |                ------- in this derive macro expansion
 LL | pub struct S((), A);
-   |              ^^
-note: inside `_`
-  --> $DIR/derive-const-use.rs:18:35
+   |                  ^
    |
-LL | const _: () = assert!(S((), A) == S::default());
-   |                                   ^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 8 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-use.rs:16:14
+   |
+LL | #[derive_const(Default, PartialEq)]
+   |                         --------- in this derive macro expansion
+LL | pub struct S((), A);
+   |              ^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-use.rs:16:18
+   |
+LL | #[derive_const(Default, PartialEq)]
+   |                         --------- in this derive macro expansion
+LL | pub struct S((), A);
+   |                  ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 13 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0080, E0635.
-For more information about an error, try `rustc --explain E0080`.
+Some errors have detailed explanations: E0015, E0635.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
index addce8dcd6c75..33e7e08bb2358 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
@@ -30,5 +30,25 @@ LL | #[derive_const(PartialEq)]
    |
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-with-params.rs:8:23
+   |
+LL | #[derive_const(PartialEq)]
+   |                --------- in this derive macro expansion
+LL | pub struct Reverse<T>(T);
+   |                       ^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/derive-const-with-params.rs:11:5
+   |
+LL |     a == b
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 5 previous errors; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
index 3debc22098afc..8f8e9f065845e 100644
--- a/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
+++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
@@ -1,5 +1,3 @@
-//@ check-pass
-// FIXME(effects) this shouldn't pass
 //@ compile-flags: -Znext-solver
 #![feature(const_closures, const_trait_impl, effects)]
 #![allow(incomplete_features)]
@@ -14,5 +12,6 @@ impl Foo for () {
 
 fn main() {
     (const || { (()).foo() })();
-    // FIXME(effects) ~^ ERROR: cannot call non-const fn
+    //~^ ERROR: cannot call non-const fn `<() as Foo>::foo` in constant functions
+    // FIXME(effects) this should probably say constant closures
 }
diff --git a/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr
new file mode 100644
index 0000000000000..243e94087bbdd
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions
+  --> $DIR/const_closure-const_trait_impl-ice-113381.rs:14:22
+   |
+LL |     (const || { (()).foo() })();
+   |                      ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
index 9a9016de3a0d9..ab530b109e158 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
@@ -10,6 +10,7 @@ const fn test() -> impl ~const Fn() {
             [first, remainder @ ..] => {
                 assert_eq!(first, &b'f');
                 //~^ ERROR cannot call non-const fn
+                //~| ERROR cannot call non-const operator
             }
             [] => panic!(),
         }
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
index 526746eec7346..edfdf8b5f7813 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
@@ -36,6 +36,15 @@ LL | const fn test() -> impl ~const Fn() {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/ice-112822-expected-type-for-param.rs:11:17
+   |
+LL |                 assert_eq!(first, &b'f');
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions
   --> $DIR/ice-112822-expected-type-for-param.rs:11:17
    |
@@ -45,7 +54,7 @@ LL |                 assert_eq!(first, &b'f');
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0015, E0658.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/generic-bound.stderr b/tests/ui/traits/const-traits/generic-bound.stderr
index 2baac1d2a168e..0444c3195773e 100644
--- a/tests/ui/traits/const-traits/generic-bound.stderr
+++ b/tests/ui/traits/const-traits/generic-bound.stderr
@@ -14,10 +14,6 @@ LL |     arg + arg
    |     ^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/const-traits/hir-const-check.rs b/tests/ui/traits/const-traits/hir-const-check.rs
index b3df6495afc97..0ffd60682b0c7 100644
--- a/tests/ui/traits/const-traits/hir-const-check.rs
+++ b/tests/ui/traits/const-traits/hir-const-check.rs
@@ -12,6 +12,8 @@ pub trait MyTrait {
 impl const MyTrait for () {
     fn method(&self) -> Option<()> {
         Some(())?; //~ ERROR `?` is not allowed in a `const fn`
+        //~^ ERROR `?` cannot determine the branch of `Option<()>` in constant functions
+        //~| ERROR `?` cannot convert from residual of `Option<()>` in constant functions
         None
     }
 }
diff --git a/tests/ui/traits/const-traits/hir-const-check.stderr b/tests/ui/traits/const-traits/hir-const-check.stderr
index 19ea734efb777..a22ac2c973979 100644
--- a/tests/ui/traits/const-traits/hir-const-check.stderr
+++ b/tests/ui/traits/const-traits/hir-const-check.stderr
@@ -17,6 +17,27 @@ LL |         Some(())?;
    = help: add `#![feature(const_try)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 1 previous error; 1 warning emitted
+error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions
+  --> $DIR/hir-const-check.rs:14:9
+   |
+LL |         Some(())?;
+   |         ^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
+  --> $DIR/hir-const-check.rs:14:9
+   |
+LL |         Some(())?;
+   |         ^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
index 717c0e7c08829..da97a0e70ed73 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
@@ -18,6 +18,8 @@ impl const Try for TryMe {
 
 const fn t() -> TryMe {
     TryMe?;
+    //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions
+    //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions
     TryMe
 }
 
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
index e49436c8f0f78..0ca16a1be409f 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
@@ -38,6 +38,23 @@ LL | impl const Try for TryMe {
    = help: implement the missing item: `fn from_output(_: <Self as Try>::Output) -> Self { todo!() }`
    = help: implement the missing item: `fn branch(self) -> ControlFlow<<Self as Try>::Residual, <Self as Try>::Output> { todo!() }`
 
-error: aborting due to 5 previous errors
+error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions
+  --> $DIR/ice-126148-failed-to-normalize.rs:20:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions
+  --> $DIR/ice-126148-failed-to-normalize.rs:20:5
+   |
+LL |     TryMe?;
+   |     ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0046`.
+Some errors have detailed explanations: E0015, E0046.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
index e3adcce17b42c..8638c4bbd7f18 100644
--- a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
+++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
@@ -25,6 +25,7 @@ impl Trait for () {
 
 const fn foo() {
     ().foo();
+    //~^ ERROR cannot call non-const fn `<() as Trait>::foo` in constant functions
 }
 
 const UWU: () = foo();
diff --git a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
index 2e7801c0b8acd..096b00dd30293 100644
--- a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
+++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
@@ -16,6 +16,15 @@ LL |     fn foo(self);
 LL |     fn foo<T>(self) {
    |            ^ found 1 type parameter
 
-error: aborting due to 1 previous error; 1 warning emitted
+error[E0015]: cannot call non-const fn `<() as Trait>::foo` in constant functions
+  --> $DIR/inline-incorrect-early-bound-in-ctfe.rs:27:8
+   |
+LL |     ().foo();
+   |        ^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0049`.
+Some errors have detailed explanations: E0015, E0049.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/issue-102985.stderr b/tests/ui/traits/const-traits/issue-102985.stderr
index 8401d1bd4f6c3..7c5c5acf20799 100644
--- a/tests/ui/traits/const-traits/issue-102985.stderr
+++ b/tests/ui/traits/const-traits/issue-102985.stderr
@@ -6,10 +6,6 @@ LL |         n => n(),
    |
    = note: closures need an RFC before allowed to be called in constants
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/issue-88155.stderr b/tests/ui/traits/const-traits/issue-88155.stderr
index afe1ea3b1b732..157b54214fa73 100644
--- a/tests/ui/traits/const-traits/issue-88155.stderr
+++ b/tests/ui/traits/const-traits/issue-88155.stderr
@@ -5,10 +5,6 @@ LL |     T::assoc()
    |     ^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
index c7d211516614a..89e59e5db6ed3 100644
--- a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
+++ b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
@@ -6,10 +6,6 @@ LL |         "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in
    |
    = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
index 0f5ecac3891e9..89e59e5db6ed3 100644
--- a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
+++ b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
@@ -6,10 +6,6 @@ LL |         "a" => (), //FIXME [gated]~ ERROR can't compare `str` with `str` in
    |
    = note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
index c362a1077e339..97ad83130d444 100644
--- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
@@ -5,10 +5,6 @@ LL |     (const || { (()).foo() })();
    |                      ^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
index 2803c37646b14..08a40fe65bfae 100644
--- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
@@ -19,10 +19,6 @@ LL |         B::from(self)
    |         ^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/std-impl-gate.gated.stderr b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
index d761fdce4bf0a..f3b171307618d 100644
--- a/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
+++ b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
@@ -11,10 +11,6 @@ LL |     Default::default()
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
-   |
-LL + #![feature(effects)]
-   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/const-traits/std-impl-gate.stock.stderr b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
index b63ea695fc22a..7240b5f4a94c2 100644
--- a/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
+++ b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
@@ -5,10 +5,6 @@ LL |     Default::default()
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
index 48bb1907be2eb..6277966b08e9b 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
@@ -32,5 +32,14 @@ LL | trait Bar: ~const Foo {}
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 4 previous errors
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-2.rs:21:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
index a0848fe520e85..60660ecc2797d 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
@@ -36,5 +36,14 @@ LL | trait Bar: ~const Foo {}
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 5 previous errors
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-2.rs:21:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs
index 0ea61f4ae2001..1e41d709d6b32 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs
@@ -20,6 +20,7 @@ trait Bar: ~const Foo {}
 const fn foo<T: Bar>(x: &T) {
     x.a();
     //[yy,yn]~^ ERROR the trait bound `T: ~const Foo`
+    //[nn,ny]~^^ ERROR cannot call non-const fn `<T as Foo>::a` in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
index 294545014bf5e..b39bf8d8e1588 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
@@ -46,5 +46,14 @@ LL | const fn foo<T: ~const Bar>(x: &T) {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 6 previous errors
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:25:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
index 54bb6c5ca4418..187cd998d95a2 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
@@ -36,5 +36,14 @@ LL | trait Bar: ~const Foo {}
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 5 previous errors
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:25:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs
index a9b08e6edcdc6..414337956e217 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs
@@ -24,6 +24,7 @@ const fn foo<T: ~const Bar>(x: &T) {
     //[yn,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
     x.a();
     //[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied
+    //[nn,ny]~^^ ERROR: cannot call non-const fn `<T as Foo>::a` in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
index 49fbef9aaa29f..5806b6d6fd215 100644
--- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr
+++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
@@ -16,5 +16,22 @@ LL | impl const FromResidual for T {
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error: aborting due to 2 previous errors
+error[E0015]: `?` cannot determine the branch of `T` in constant functions
+  --> $DIR/trait-default-body-stability.rs:45:9
+   |
+LL |         T?
+   |         ^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: `?` cannot convert from residual of `T` in constant functions
+  --> $DIR/trait-default-body-stability.rs:45:9
+   |
+LL |         T?
+   |         ^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index 8a765c21624e6..5e32d5c429ef0 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -675,10 +675,6 @@ LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error[E0015]: cannot call non-const fn `<Filter<std::ops::Range<i32>, {closure@$DIR/typeck_type_placeholder_item.rs:230:29: 230:32}> as Iterator>::map::<i32, {closure@$DIR/typeck_type_placeholder_item.rs:230:49: 230:52}>` in constants
   --> $DIR/typeck_type_placeholder_item.rs:230:45
@@ -687,10 +683,6 @@ LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
    |                                             ^^^^^^^^^^^^^^
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
 
 error: aborting due to 74 previous errors
 

From becd32c227fb6fd6b5e7f8a2dc51a648919b086a Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Fri, 25 Oct 2024 23:34:10 +1100
Subject: [PATCH 09/13] Add a wrapper type for raw enum values returned by LLVM

---
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 25 +++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 10e55a4f7f659..b295331f8ec38 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1,6 +1,7 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
+use std::fmt::Debug;
 use std::marker::PhantomData;
 
 use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
@@ -19,6 +20,30 @@ pub type Bool = c_uint;
 pub const True: Bool = 1 as Bool;
 pub const False: Bool = 0 as Bool;
 
+/// Wrapper for a raw enum value returned from LLVM's C APIs.
+///
+/// For C enums returned by LLVM, it's risky to use a Rust enum as the return
+/// type, because it would be UB if a later version of LLVM adds a new enum
+/// value and returns it. Instead, return this raw wrapper, then convert to the
+/// Rust-side enum explicitly.
+#[repr(transparent)]
+pub struct RawEnum<T> {
+    value: u32,
+    /// We don't own or consume a `T`, but we can produce one.
+    _rust_side_type: PhantomData<fn() -> T>,
+}
+
+impl<T: TryFrom<u32>> RawEnum<T> {
+    #[track_caller]
+    pub(crate) fn to_rust(self) -> T
+    where
+        T::Error: Debug,
+    {
+        // If this fails, the Rust-side enum is out of sync with LLVM's enum.
+        T::try_from(self.value).expect("enum value returned by LLVM should be known")
+    }
+}
+
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
 #[allow(dead_code)] // Variants constructed by C++.

From 1aed407d248417050d33f7f53ac9426fa682ca66 Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Fri, 25 Oct 2024 22:06:29 +1100
Subject: [PATCH 10/13] Use LLVM-C APIs for getting/setting linkage

---
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs   | 33 +++++---
 compiler/rustc_codegen_llvm/src/llvm/mod.rs   |  4 +-
 .../rustc_llvm/llvm-wrapper/RustWrapper.cpp   | 80 -------------------
 3 files changed, 24 insertions(+), 93 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index b295331f8ec38..3258a6c43cc62 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -5,6 +5,7 @@ use std::fmt::Debug;
 use std::marker::PhantomData;
 
 use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
+use rustc_macros::TryFromU32;
 use rustc_target::spec::SymbolVisibility;
 
 use super::RustString;
@@ -133,21 +134,31 @@ pub enum CallConv {
     AvrInterrupt = 85,
 }
 
-/// LLVMRustLinkage
-#[derive(Copy, Clone, PartialEq)]
+/// Must match the layout of `LLVMLinkage`.
+#[derive(Copy, Clone, PartialEq, TryFromU32)]
 #[repr(C)]
 pub enum Linkage {
     ExternalLinkage = 0,
     AvailableExternallyLinkage = 1,
     LinkOnceAnyLinkage = 2,
     LinkOnceODRLinkage = 3,
-    WeakAnyLinkage = 4,
-    WeakODRLinkage = 5,
-    AppendingLinkage = 6,
-    InternalLinkage = 7,
-    PrivateLinkage = 8,
-    ExternalWeakLinkage = 9,
-    CommonLinkage = 10,
+    #[deprecated = "marked obsolete by LLVM"]
+    LinkOnceODRAutoHideLinkage = 4,
+    WeakAnyLinkage = 5,
+    WeakODRLinkage = 6,
+    AppendingLinkage = 7,
+    InternalLinkage = 8,
+    PrivateLinkage = 9,
+    #[deprecated = "marked obsolete by LLVM"]
+    DLLImportLinkage = 10,
+    #[deprecated = "marked obsolete by LLVM"]
+    DLLExportLinkage = 11,
+    ExternalWeakLinkage = 12,
+    #[deprecated = "marked obsolete by LLVM"]
+    GhostLinkage = 13,
+    CommonLinkage = 14,
+    LinkerPrivateLinkage = 15,
+    LinkerPrivateWeakLinkage = 16,
 }
 
 // LLVMRustVisibility
@@ -970,6 +981,8 @@ unsafe extern "C" {
 
     // Operations on global variables, functions, and aliases (globals)
     pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
+    pub fn LLVMGetLinkage(Global: &Value) -> RawEnum<Linkage>;
+    pub fn LLVMSetLinkage(Global: &Value, RustLinkage: Linkage);
     pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
     pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
     pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
@@ -1546,8 +1559,6 @@ unsafe extern "C" {
     ) -> bool;
 
     // Operations on global variables, functions, and aliases (globals)
-    pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage;
-    pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage);
     pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
     pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
     pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 235b5794b8c54..3eef9e623614b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -233,12 +233,12 @@ pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
 }
 
 pub fn get_linkage(llglobal: &Value) -> Linkage {
-    unsafe { LLVMRustGetLinkage(llglobal) }
+    unsafe { LLVMGetLinkage(llglobal) }.to_rust()
 }
 
 pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
     unsafe {
-        LLVMRustSetLinkage(llglobal, linkage);
+        LLVMSetLinkage(llglobal, linkage);
     }
 }
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index cb75888abd76d..6c3fa9622f3b8 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1619,86 +1619,6 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
   unwrap(B)->SetInsertPoint(unwrap(BB), Point);
 }
 
-enum class LLVMRustLinkage {
-  ExternalLinkage = 0,
-  AvailableExternallyLinkage = 1,
-  LinkOnceAnyLinkage = 2,
-  LinkOnceODRLinkage = 3,
-  WeakAnyLinkage = 4,
-  WeakODRLinkage = 5,
-  AppendingLinkage = 6,
-  InternalLinkage = 7,
-  PrivateLinkage = 8,
-  ExternalWeakLinkage = 9,
-  CommonLinkage = 10,
-};
-
-static LLVMRustLinkage toRust(LLVMLinkage Linkage) {
-  switch (Linkage) {
-  case LLVMExternalLinkage:
-    return LLVMRustLinkage::ExternalLinkage;
-  case LLVMAvailableExternallyLinkage:
-    return LLVMRustLinkage::AvailableExternallyLinkage;
-  case LLVMLinkOnceAnyLinkage:
-    return LLVMRustLinkage::LinkOnceAnyLinkage;
-  case LLVMLinkOnceODRLinkage:
-    return LLVMRustLinkage::LinkOnceODRLinkage;
-  case LLVMWeakAnyLinkage:
-    return LLVMRustLinkage::WeakAnyLinkage;
-  case LLVMWeakODRLinkage:
-    return LLVMRustLinkage::WeakODRLinkage;
-  case LLVMAppendingLinkage:
-    return LLVMRustLinkage::AppendingLinkage;
-  case LLVMInternalLinkage:
-    return LLVMRustLinkage::InternalLinkage;
-  case LLVMPrivateLinkage:
-    return LLVMRustLinkage::PrivateLinkage;
-  case LLVMExternalWeakLinkage:
-    return LLVMRustLinkage::ExternalWeakLinkage;
-  case LLVMCommonLinkage:
-    return LLVMRustLinkage::CommonLinkage;
-  default:
-    report_fatal_error("Invalid LLVMRustLinkage value!");
-  }
-}
-
-static LLVMLinkage fromRust(LLVMRustLinkage Linkage) {
-  switch (Linkage) {
-  case LLVMRustLinkage::ExternalLinkage:
-    return LLVMExternalLinkage;
-  case LLVMRustLinkage::AvailableExternallyLinkage:
-    return LLVMAvailableExternallyLinkage;
-  case LLVMRustLinkage::LinkOnceAnyLinkage:
-    return LLVMLinkOnceAnyLinkage;
-  case LLVMRustLinkage::LinkOnceODRLinkage:
-    return LLVMLinkOnceODRLinkage;
-  case LLVMRustLinkage::WeakAnyLinkage:
-    return LLVMWeakAnyLinkage;
-  case LLVMRustLinkage::WeakODRLinkage:
-    return LLVMWeakODRLinkage;
-  case LLVMRustLinkage::AppendingLinkage:
-    return LLVMAppendingLinkage;
-  case LLVMRustLinkage::InternalLinkage:
-    return LLVMInternalLinkage;
-  case LLVMRustLinkage::PrivateLinkage:
-    return LLVMPrivateLinkage;
-  case LLVMRustLinkage::ExternalWeakLinkage:
-    return LLVMExternalWeakLinkage;
-  case LLVMRustLinkage::CommonLinkage:
-    return LLVMCommonLinkage;
-  }
-  report_fatal_error("Invalid LLVMRustLinkage value!");
-}
-
-extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
-  return toRust(LLVMGetLinkage(V));
-}
-
-extern "C" void LLVMRustSetLinkage(LLVMValueRef V,
-                                   LLVMRustLinkage RustLinkage) {
-  LLVMSetLinkage(V, fromRust(RustLinkage));
-}
-
 extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
   auto C = unwrap<llvm::ConstantInt>(CV);
   if (C->getBitWidth() > 64)

From 3e51f6fcf8074f1bde43aa414056258fa174c37d Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Fri, 25 Oct 2024 22:26:15 +1100
Subject: [PATCH 11/13] Use LLVM-C APIs for getting/setting visibility

---
 compiler/rustc_codegen_llvm/src/llvm/ffi.rs   |  8 ++--
 compiler/rustc_codegen_llvm/src/llvm/mod.rs   |  4 +-
 .../rustc_llvm/llvm-wrapper/RustWrapper.cpp   | 39 -------------------
 3 files changed, 6 insertions(+), 45 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 3258a6c43cc62..acc6607683396 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -161,9 +161,9 @@ pub enum Linkage {
     LinkerPrivateWeakLinkage = 16,
 }
 
-// LLVMRustVisibility
+/// Must match the layout of `LLVMVisibility`.
 #[repr(C)]
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, TryFromU32)]
 pub enum Visibility {
     Default = 0,
     Hidden = 1,
@@ -984,6 +984,8 @@ unsafe extern "C" {
     pub fn LLVMGetLinkage(Global: &Value) -> RawEnum<Linkage>;
     pub fn LLVMSetLinkage(Global: &Value, RustLinkage: Linkage);
     pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
+    pub fn LLVMGetVisibility(Global: &Value) -> RawEnum<Visibility>;
+    pub fn LLVMSetVisibility(Global: &Value, Viz: Visibility);
     pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
     pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
     pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);
@@ -1559,8 +1561,6 @@ unsafe extern "C" {
     ) -> bool;
 
     // Operations on global variables, functions, and aliases (globals)
-    pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
-    pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
     pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool);
 
     // Operations on global variables
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 3eef9e623614b..6aac2eea81d0a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -243,12 +243,12 @@ pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
 }
 
 pub fn get_visibility(llglobal: &Value) -> Visibility {
-    unsafe { LLVMRustGetVisibility(llglobal) }
+    unsafe { LLVMGetVisibility(llglobal) }.to_rust()
 }
 
 pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
     unsafe {
-        LLVMRustSetVisibility(llglobal, visibility);
+        LLVMSetVisibility(llglobal, visibility);
     }
 }
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 6c3fa9622f3b8..9f941637d8c17 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1646,45 +1646,6 @@ extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext,
   return true;
 }
 
-enum class LLVMRustVisibility {
-  Default = 0,
-  Hidden = 1,
-  Protected = 2,
-};
-
-static LLVMRustVisibility toRust(LLVMVisibility Vis) {
-  switch (Vis) {
-  case LLVMDefaultVisibility:
-    return LLVMRustVisibility::Default;
-  case LLVMHiddenVisibility:
-    return LLVMRustVisibility::Hidden;
-  case LLVMProtectedVisibility:
-    return LLVMRustVisibility::Protected;
-  }
-  report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-static LLVMVisibility fromRust(LLVMRustVisibility Vis) {
-  switch (Vis) {
-  case LLVMRustVisibility::Default:
-    return LLVMDefaultVisibility;
-  case LLVMRustVisibility::Hidden:
-    return LLVMHiddenVisibility;
-  case LLVMRustVisibility::Protected:
-    return LLVMProtectedVisibility;
-  }
-  report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) {
-  return toRust(LLVMGetVisibility(V));
-}
-
-extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
-                                      LLVMRustVisibility RustVisibility) {
-  LLVMSetVisibility(V, fromRust(RustVisibility));
-}
-
 extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) {
   unwrap<GlobalValue>(Global)->setDSOLocal(is_dso_local);
 }

From 0d653a5866720570b96260ab69b732d241ec346e Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Sat, 26 Oct 2024 17:37:04 +1100
Subject: [PATCH 12/13] coverage: Add links to LLVM docs for the coverage
 mapping format

---
 compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 5b39d078e0d7e..8edd788ee36ca 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -349,6 +349,7 @@ fn generate_covmap_record<'ll>(
     llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
     llvm::set_section(llglobal, &covmap_section_name);
     // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    // <https://llvm.org/docs/CoverageMappingFormat.html>
     llvm::set_alignment(llglobal, Align::EIGHT);
     cx.add_used_global(llglobal);
 }
@@ -400,6 +401,7 @@ fn generate_covfun_record(
     llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
     llvm::set_section(llglobal, cx.covfun_section_name());
     // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    // <https://llvm.org/docs/CoverageMappingFormat.html>
     llvm::set_alignment(llglobal, Align::EIGHT);
     if cx.target_spec().supports_comdat() {
         llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);

From 867640e24d9a54b5a4251e2827c83131f4574bb5 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 26 Oct 2024 09:48:39 +0200
Subject: [PATCH 13/13] x86 target features: make pclmulqdq imply sse2

---
 compiler/rustc_target/src/target_features.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index e92366d5c5c3f..910cafbdf3bda 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -316,7 +316,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
     ("lzcnt", Stable, &[]),
     ("movbe", Stable, &[]),
-    ("pclmulqdq", Stable, &[]),
+    ("pclmulqdq", Stable, &["sse2"]),
     ("popcnt", Stable, &[]),
     ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
     ("rdrand", Stable, &[]),