about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-25 06:14:15 +0000
committerbors <bors@rust-lang.org>2022-05-25 06:14:15 +0000
commitcbdce423201f1b155c46f3ec690a644cf3b4ba53 (patch)
treecef7952def48410cda70c688087adbb77b4974c8
parent9fadabc879e0b16214e8216c1a63a597d1d5d36b (diff)
parent70bdfc1d799b84b05905397044c45da51d0c2661 (diff)
downloadrust-cbdce423201f1b155c46f3ec690a644cf3b4ba53.tar.gz
rust-cbdce423201f1b155c46f3ec690a644cf3b4ba53.zip
Auto merge of #97382 - Dylan-DPC:rollup-2t4ov4z, r=Dylan-DPC
Rollup of 5 pull requests

Successful merges:

 - #93604 (Make llvm-libunwind a per-target option)
 - #97026 (Change orderings of `Debug` for the Atomic types to `Relaxed`.)
 - #97105 (Add tests for lint on type dependent on consts)
 - #97323 (Introduce stricter checks for might_permit_raw_init under a debug flag )
 - #97379 (Add aliases for `current_dir`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs14
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_target/src/abi/mod.rs59
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs266
-rw-r--r--config.toml.example25
-rw-r--r--library/core/src/sync/atomic.rs6
-rw-r--r--library/std/src/env.rs3
-rw-r--r--src/bootstrap/compile.rs2
-rw-r--r--src/bootstrap/config.rs23
-rw-r--r--src/bootstrap/lib.rs2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr39
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr34
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs25
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/no_dependence.rs13
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs44
18 files changed, 401 insertions, 180 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index f8c69d46d1f..6937e658ed5 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -58,6 +58,7 @@ pub(crate) use llvm::codegen_llvm_intrinsic_call;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_target::abi::InitKind;
 
 use crate::prelude::*;
 use cranelift_codegen::ir::AtomicRmwOp;
@@ -671,7 +672,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 return;
             }
 
-            if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true) {
+            if intrinsic == sym::assert_zero_valid
+                && !layout.might_permit_raw_init(
+                    fx,
+                    InitKind::Zero,
+                    fx.tcx.sess.opts.debugging_opts.strict_init_checks) {
+
                 with_no_trimmed_paths!({
                     crate::base::codegen_panic(
                         fx,
@@ -682,7 +688,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 return;
             }
 
-            if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false) {
+            if intrinsic == sym::assert_uninit_valid
+                && !layout.might_permit_raw_init(
+                    fx,
+                    InitKind::Uninit,
+                    fx.tcx.sess.opts.debugging_opts.strict_init_checks) {
+
                 with_no_trimmed_paths!({
                     crate::base::codegen_panic(
                         fx,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index f1007ba1578..03ef6d50d44 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -22,7 +22,7 @@ use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
 use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
-use rustc_target::abi::{self, HasDataLayout, WrappingRange};
+use rustc_target::abi::{self, HasDataLayout, InitKind, WrappingRange};
 use rustc_target::spec::abi::Abi;
 
 /// Used by `FunctionCx::codegen_terminator` for emitting common patterns
@@ -521,6 +521,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         source_info: mir::SourceInfo,
         target: Option<mir::BasicBlock>,
         cleanup: Option<mir::BasicBlock>,
+        strict_validity: bool,
     ) -> bool {
         // Emit a panic or a no-op for `assert_*` intrinsics.
         // These are intrinsics that compile to panics so that we can get a message
@@ -543,8 +544,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let layout = bx.layout_of(ty);
             let do_panic = match intrinsic {
                 Inhabited => layout.abi.is_uninhabited(),
-                ZeroValid => !layout.might_permit_raw_init(bx, /*zero:*/ true),
-                UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false),
+                ZeroValid => !layout.might_permit_raw_init(bx, InitKind::Zero, strict_validity),
+                UninitValid => !layout.might_permit_raw_init(bx, InitKind::Uninit, strict_validity),
             };
             if do_panic {
                 let msg_str = with_no_visible_paths!({
@@ -678,6 +679,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             source_info,
             target,
             cleanup,
+            self.cx.tcx().sess.opts.debugging_opts.strict_init_checks,
         ) {
             return;
         }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index b747be3a636..bf1cf816ddd 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, Align, Primitive, Size};
+use rustc_target::abi::{Abi, Align, InitKind, Primitive, Size};
 
 use super::{
     util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
@@ -408,7 +408,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     )?;
                 }
                 if intrinsic_name == sym::assert_zero_valid
-                    && !layout.might_permit_raw_init(self, /*zero:*/ true)
+                    && !layout.might_permit_raw_init(
+                        self,
+                        InitKind::Zero,
+                        self.tcx.sess.opts.debugging_opts.strict_init_checks,
+                    )
                 {
                     M::abort(
                         self,
@@ -419,7 +423,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     )?;
                 }
                 if intrinsic_name == sym::assert_uninit_valid
-                    && !layout.might_permit_raw_init(self, /*zero:*/ false)
+                    && !layout.might_permit_raw_init(
+                        self,
+                        InitKind::Uninit,
+                        self.tcx.sess.opts.debugging_opts.strict_init_checks,
+                    )
                 {
                     M::abort(
                         self,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 12e00ef5114..66198dff2ae 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1495,6 +1495,8 @@ options! {
         "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
     stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
         "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
+    strict_init_checks: bool = (false, parse_bool, [TRACKED],
+        "control if mem::uninitialized and mem::zeroed panic on more UB"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
     split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index a2cd3c4c468..a771369c807 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -894,6 +894,15 @@ impl Scalar {
             Scalar::Union { .. } => true,
         }
     }
+
+    /// Returns `true` if this type can be left uninit.
+    #[inline]
+    pub fn is_uninit_valid(&self) -> bool {
+        match *self {
+            Scalar::Initialized { .. } => false,
+            Scalar::Union { .. } => true,
+        }
+    }
 }
 
 /// Describes how the fields of a type are located in memory.
@@ -1355,6 +1364,14 @@ pub struct PointeeInfo {
     pub address_space: AddressSpace,
 }
 
+/// Used in `might_permit_raw_init` to indicate the kind of initialisation
+/// that is checked to be valid
+#[derive(Copy, Clone, Debug)]
+pub enum InitKind {
+    Zero,
+    Uninit,
+}
+
 /// Trait that needs to be implemented by the higher-level type representation
 /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
 pub trait TyAbiInterface<'a, C>: Sized {
@@ -1461,26 +1478,37 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
 
     /// Determines if this type permits "raw" initialization by just transmuting some
     /// memory into an instance of `T`.
-    /// `zero` indicates if the memory is zero-initialized, or alternatively
-    /// left entirely uninitialized.
+    ///
+    /// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
+    ///
+    /// `strict` is an opt-in debugging flag added in #97323 that enables more checks.
+    ///
     /// This is conservative: in doubt, it will answer `true`.
     ///
     /// FIXME: Once we removed all the conservatism, we could alternatively
     /// create an all-0/all-undef constant and run the const value validator to see if
     /// this is a valid value for the given type.
-    pub fn might_permit_raw_init<C>(self, cx: &C, zero: bool) -> bool
+    pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind, strict: bool) -> bool
     where
         Self: Copy,
         Ty: TyAbiInterface<'a, C>,
         C: HasDataLayout,
     {
         let scalar_allows_raw_init = move |s: Scalar| -> bool {
-            if zero {
-                // The range must contain 0.
-                s.valid_range(cx).contains(0)
-            } else {
-                // The range must include all values.
-                s.is_always_valid(cx)
+            match init_kind {
+                InitKind::Zero => {
+                    // The range must contain 0.
+                    s.valid_range(cx).contains(0)
+                }
+                InitKind::Uninit => {
+                    if strict {
+                        // The type must be allowed to be uninit (which means "is a union").
+                        s.is_uninit_valid()
+                    } else {
+                        // The range must include all values.
+                        s.is_always_valid(cx)
+                    }
+                }
             }
         };
 
@@ -1500,12 +1528,19 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
         // If we have not found an error yet, we need to recursively descend into fields.
         match &self.fields {
             FieldsShape::Primitive | FieldsShape::Union { .. } => {}
-            FieldsShape::Array { .. } => {
-                // FIXME(#66151): For now, we are conservative and do not check arrays.
+            FieldsShape::Array { count, .. } => {
+                // FIXME(#66151): For now, we are conservative and do not check arrays by default.
+                if strict
+                    && *count > 0
+                    && !self.field(cx, 0).might_permit_raw_init(cx, init_kind, strict)
+                {
+                    // Found non empty array with a type that is unhappy about this kind of initialization
+                    return false;
+                }
             }
             FieldsShape::Arbitrary { offsets, .. } => {
                 for idx in 0..offsets.len() {
-                    if !self.field(cx, idx).might_permit_raw_init(cx, zero) {
+                    if !self.field(cx, idx).might_permit_raw_init(cx, init_kind, strict) {
                         // We found a field that is unhappy with this kind of initialization.
                         return false;
                     }
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index f46e8ff0004..539e94993ae 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -20,6 +20,7 @@
 #![feature(label_break_value)]
 #![feature(let_chains)]
 #![feature(let_else)]
+#![feature(if_let_guard)]
 #![feature(never_type)]
 #![recursion_limit = "512"] // For rustdoc
 
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 27ce08ea045..0dea2c3d8bf 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -39,150 +39,148 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     let tcx = infcx.tcx;
 
     if tcx.features().generic_const_exprs {
-        match AbstractConst::new(tcx, uv)? {
-            // We are looking at a generic abstract constant.
-            Some(ct) => {
-                if satisfied_from_param_env(tcx, ct, param_env)? {
-                    return Ok(());
-                }
-
-                // We were unable to unify the abstract constant with
-                // a constant found in the caller bounds, there are
-                // now three possible cases here.
-                #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-                enum FailureKind {
-                    /// The abstract const still references an inference
-                    /// variable, in this case we return `TooGeneric`.
-                    MentionsInfer,
-                    /// The abstract const references a generic parameter,
-                    /// this means that we emit an error here.
-                    MentionsParam,
-                    /// The substs are concrete enough that we can simply
-                    /// try and evaluate the given constant.
-                    Concrete,
-                }
-                let mut failure_kind = FailureKind::Concrete;
-                walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
-                    Node::Leaf(leaf) => {
-                        if leaf.has_infer_types_or_consts() {
-                            failure_kind = FailureKind::MentionsInfer;
-                        } else if leaf.has_param_types_or_consts() {
-                            failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
-                        }
-
-                        ControlFlow::CONTINUE
+        if let Some(ct) = AbstractConst::new(tcx, uv)? {
+            if satisfied_from_param_env(tcx, ct, param_env)? {
+                return Ok(());
+            }
+
+            // We were unable to unify the abstract constant with
+            // a constant found in the caller bounds, there are
+            // now three possible cases here.
+            #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+            enum FailureKind {
+                /// The abstract const still references an inference
+                /// variable, in this case we return `TooGeneric`.
+                MentionsInfer,
+                /// The abstract const references a generic parameter,
+                /// this means that we emit an error here.
+                MentionsParam,
+                /// The substs are concrete enough that we can simply
+                /// try and evaluate the given constant.
+                Concrete,
+            }
+            let mut failure_kind = FailureKind::Concrete;
+            walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
+                Node::Leaf(leaf) => {
+                    if leaf.has_infer_types_or_consts() {
+                        failure_kind = FailureKind::MentionsInfer;
+                    } else if leaf.has_param_types_or_consts() {
+                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
                     }
-                    Node::Cast(_, _, ty) => {
-                        if ty.has_infer_types_or_consts() {
-                            failure_kind = FailureKind::MentionsInfer;
-                        } else if ty.has_param_types_or_consts() {
-                            failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
-                        }
 
-                        ControlFlow::CONTINUE
-                    }
-                    Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
-                        ControlFlow::CONTINUE
+                    ControlFlow::CONTINUE
+                }
+                Node::Cast(_, _, ty) => {
+                    if ty.has_infer_types_or_consts() {
+                        failure_kind = FailureKind::MentionsInfer;
+                    } else if ty.has_param_types_or_consts() {
+                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
                     }
-                });
 
-                match failure_kind {
-                    FailureKind::MentionsInfer => {
-                        return Err(NotConstEvaluatable::MentionsInfer);
-                    }
-                    FailureKind::MentionsParam => {
-                        return Err(NotConstEvaluatable::MentionsParam);
-                    }
-                    FailureKind::Concrete => {
-                        // Dealt with below by the same code which handles this
-                        // without the feature gate.
-                    }
+                    ControlFlow::CONTINUE
                 }
-            }
-            None => {
-                // If we are dealing with a concrete constant, we can
-                // reuse the old code path and try to evaluate
-                // the constant.
-            }
-        }
-    }
+                Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
+                    ControlFlow::CONTINUE
+                }
+            });
 
-    let future_compat_lint = || {
-        if let Some(local_def_id) = uv.def.did.as_local() {
-            infcx.tcx.struct_span_lint_hir(
-                lint::builtin::CONST_EVALUATABLE_UNCHECKED,
-                infcx.tcx.hir().local_def_id_to_hir_id(local_def_id),
-                span,
-                |err| {
-                    err.build("cannot use constants which depend on generic parameters in types")
-                        .emit();
-                },
-            );
-        }
-    };
-
-    // FIXME: We should only try to evaluate a given constant here if it is fully concrete
-    // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
-    //
-    // We previously did not check this, so we only emit a future compat warning if
-    // const evaluation succeeds and the given constant is still polymorphic for now
-    // and hopefully soon change this to an error.
-    //
-    // See #74595 for more details about this.
-    let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
-
-    if concrete.is_ok() && uv.substs.has_param_types_or_consts() {
-        match infcx.tcx.def_kind(uv.def.did) {
-            DefKind::AnonConst | DefKind::InlineConst => {
-                let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
-
-                if mir_body.is_polymorphic {
-                    future_compat_lint();
+            match failure_kind {
+                FailureKind::MentionsInfer => {
+                    return Err(NotConstEvaluatable::MentionsInfer);
+                }
+                FailureKind::MentionsParam => {
+                    return Err(NotConstEvaluatable::MentionsParam);
                 }
+                // returned below
+                FailureKind::Concrete => {}
             }
-            _ => future_compat_lint(),
         }
-    }
-
-    // If we're evaluating a foreign constant, under a nightly compiler without generic
-    // const exprs, AND it would've passed if that expression had been evaluated with
-    // generic const exprs, then suggest using generic const exprs.
-    if concrete.is_err()
-        && tcx.sess.is_nightly_build()
-        && !uv.def.did.is_local()
-        && !tcx.features().generic_const_exprs
-        && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
-        && satisfied_from_param_env(tcx, ct, param_env) == Ok(true)
-    {
-        tcx.sess
-            .struct_span_fatal(
-                // Slightly better span than just using `span` alone
-                if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
-                "failed to evaluate generic const expression",
-            )
-            .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
-            .span_suggestion_verbose(
-                rustc_span::DUMMY_SP,
-                "consider enabling this feature",
-                "#![feature(generic_const_exprs)]\n".to_string(),
-                rustc_errors::Applicability::MaybeIncorrect,
-            )
-            .emit()
-    }
-
-    debug!(?concrete, "is_const_evaluatable");
-    match concrete {
-        Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
-            true => NotConstEvaluatable::MentionsInfer,
-            false => NotConstEvaluatable::MentionsParam,
-        }),
-        Err(ErrorHandled::Linted) => {
-            let reported =
-                infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
-            Err(NotConstEvaluatable::Error(reported))
+        let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
+        match concrete {
+            Err(ErrorHandled::TooGeneric) => Err(if !uv.has_infer_types_or_consts() {
+                infcx
+                    .tcx
+                    .sess
+                    .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
+                NotConstEvaluatable::MentionsParam
+            } else {
+                NotConstEvaluatable::MentionsInfer
+            }),
+            Err(ErrorHandled::Linted) => {
+                let reported = infcx
+                    .tcx
+                    .sess
+                    .delay_span_bug(span, "constant in type had error reported as lint");
+                Err(NotConstEvaluatable::Error(reported))
+            }
+            Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+            Ok(_) => Ok(()),
+        }
+    } else {
+        // FIXME: We should only try to evaluate a given constant here if it is fully concrete
+        // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
+        //
+        // We previously did not check this, so we only emit a future compat warning if
+        // const evaluation succeeds and the given constant is still polymorphic for now
+        // and hopefully soon change this to an error.
+        //
+        // See #74595 for more details about this.
+        let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
+
+        match concrete {
+          // If we're evaluating a foreign constant, under a nightly compiler without generic
+          // const exprs, AND it would've passed if that expression had been evaluated with
+          // generic const exprs, then suggest using generic const exprs.
+          Err(_) if tcx.sess.is_nightly_build()
+            && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
+            && satisfied_from_param_env(tcx, ct, param_env) == Ok(true) => {
+              tcx.sess
+                  .struct_span_fatal(
+                      // Slightly better span than just using `span` alone
+                      if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+                      "failed to evaluate generic const expression",
+                  )
+                  .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
+                  .span_suggestion_verbose(
+                      rustc_span::DUMMY_SP,
+                      "consider enabling this feature",
+                      "#![feature(generic_const_exprs)]\n".to_string(),
+                      rustc_errors::Applicability::MaybeIncorrect,
+                  )
+                  .emit()
+            }
+
+            Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
+                NotConstEvaluatable::MentionsInfer
+                } else {
+                NotConstEvaluatable::MentionsParam
+            }),
+            Err(ErrorHandled::Linted) => {
+                let reported =
+                    infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
+                Err(NotConstEvaluatable::Error(reported))
+            }
+            Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+            Ok(_) => {
+              if uv.substs.has_param_types_or_consts() {
+                  assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
+                  let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
+
+                  if mir_body.is_polymorphic {
+                      let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
+                      tcx.struct_span_lint_hir(
+                          lint::builtin::CONST_EVALUATABLE_UNCHECKED,
+                          tcx.hir().local_def_id_to_hir_id(local_def_id),
+                          span,
+                          |err| {
+                              err.build("cannot use constants which depend on generic parameters in types").emit();
+                        })
+                  }
+              }
+
+              Ok(())
+            },
         }
-        Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
-        Ok(_) => Ok(()),
     }
 }
 
diff --git a/config.toml.example b/config.toml.example
index a7968bca7be..a810e8c0e12 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -605,16 +605,9 @@ changelog-seen = 2
 # development of NLL
 #test-compare-mode = false
 
-# Use LLVM libunwind as the implementation for Rust's unwinder.
-# Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false).
-# This option only applies for Linux and Fuchsia targets.
-# On Linux target, if crt-static is not enabled, 'no' means dynamic link to
-# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind
-# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled,
-# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both
-# means static link to the in-tree build of llvm libunwind, and 'system' means
-# static link to `libunwind.a` provided by system. Due to the limitation of glibc,
-# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
+# Global default for llvm-libunwind for all targets. See the target-specific
+# documentation for llvm-libunwind below. Note that the target-specific
+# option will override this if set.
 #llvm-libunwind = 'no'
 
 # Enable Windows Control Flow Guard checks in the standard library.
@@ -671,6 +664,18 @@ changelog-seen = 2
 # not, you can specify an explicit file name for it.
 #llvm-filecheck = "/path/to/llvm-version/bin/FileCheck"
 
+# Use LLVM libunwind as the implementation for Rust's unwinder.
+# Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false).
+# This option only applies for Linux and Fuchsia targets.
+# On Linux target, if crt-static is not enabled, 'no' means dynamic link to
+# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind
+# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled,
+# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both
+# means static link to the in-tree build of llvm libunwind, and 'system' means
+# static link to `libunwind.a` provided by system. Due to the limitation of glibc,
+# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
+#llvm-libunwind = 'no' if Linux, 'in-tree' if Fuchsia
+
 # If this target is for Android, this option will be required to specify where
 # the NDK for the target lives. This is used to find the C compiler to link and
 # build native code.
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 36df5c3beb3..43cfb1bb640 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -1517,7 +1517,7 @@ macro_rules! atomic_int {
         #[$stable_debug]
         impl fmt::Debug for $atomic_type {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
+                fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
             }
         }
 
@@ -2996,7 +2996,7 @@ pub fn compiler_fence(order: Ordering) {
 #[stable(feature = "atomic_debug", since = "1.3.0")]
 impl fmt::Debug for AtomicBool {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
+        fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
     }
 }
 
@@ -3004,7 +3004,7 @@ impl fmt::Debug for AtomicBool {
 #[stable(feature = "atomic_debug", since = "1.3.0")]
 impl<T> fmt::Debug for AtomicPtr<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
+        fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
     }
 }
 
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 4027a71a06c..463f714064c 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -49,6 +49,9 @@ use crate::sys::os as os_imp;
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "pwd")]
+#[doc(alias = "getcwd")]
+#[doc(alias = "GetCurrentDirectory")]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn current_dir() -> io::Result<PathBuf> {
     os_imp::getcwd()
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 7a8c7fee5f5..0b430f64e1e 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -176,7 +176,7 @@ fn copy_third_party_objects(
 
     if target == "x86_64-fortanix-unknown-sgx"
         || target.contains("pc-windows-gnullvm")
-        || builder.config.llvm_libunwind == LlvmLibunwind::InTree
+        || builder.config.llvm_libunwind(target) == LlvmLibunwind::InTree
             && (target.contains("linux") || target.contains("fuchsia"))
     {
         let libunwind_path =
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index f9acd52274f..843d276cd7a 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -67,7 +67,6 @@ pub struct Config {
     pub rustc_error_format: Option<String>,
     pub json_output: bool,
     pub test_compare_mode: bool,
-    pub llvm_libunwind: LlvmLibunwind,
     pub color: Color,
     pub patch_binaries_for_nix: bool,
 
@@ -151,6 +150,7 @@ pub struct Config {
     pub rust_profile_generate: Option<String>,
     pub llvm_profile_use: Option<String>,
     pub llvm_profile_generate: bool,
+    pub llvm_libunwind_default: Option<LlvmLibunwind>,
 
     pub build: TargetSelection,
     pub hosts: Vec<TargetSelection>,
@@ -342,6 +342,7 @@ pub struct Target {
     pub llvm_config: Option<PathBuf>,
     /// Some(path to FileCheck) if one was specified.
     pub llvm_filecheck: Option<PathBuf>,
+    pub llvm_libunwind: Option<LlvmLibunwind>,
     pub cc: Option<PathBuf>,
     pub cxx: Option<PathBuf>,
     pub ar: Option<PathBuf>,
@@ -680,6 +681,7 @@ define_config! {
         linker: Option<String> = "linker",
         llvm_config: Option<String> = "llvm-config",
         llvm_filecheck: Option<String> = "llvm-filecheck",
+        llvm_libunwind: Option<String> = "llvm-libunwind",
         android_ndk: Option<String> = "android-ndk",
         sanitizers: Option<bool> = "sanitizers",
         profiler: Option<bool> = "profiler",
@@ -1043,10 +1045,6 @@ impl Config {
             set(&mut config.rust_rpath, rust.rpath);
             set(&mut config.jemalloc, rust.jemalloc);
             set(&mut config.test_compare_mode, rust.test_compare_mode);
-            config.llvm_libunwind = rust
-                .llvm_libunwind
-                .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"))
-                .unwrap_or_default();
             set(&mut config.backtrace, rust.backtrace);
             set(&mut config.channel, rust.channel);
             config.description = rust.description;
@@ -1069,6 +1067,9 @@ impl Config {
             config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
             set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
             set(&mut config.control_flow_guard, rust.control_flow_guard);
+            config.llvm_libunwind_default = rust
+                .llvm_libunwind
+                .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
 
             if let Some(ref backends) = rust.codegen_backends {
                 config.rust_codegen_backends =
@@ -1095,6 +1096,10 @@ impl Config {
                 if let Some(ref s) = cfg.llvm_filecheck {
                     target.llvm_filecheck = Some(config.src.join(s));
                 }
+                target.llvm_libunwind = cfg
+                    .llvm_libunwind
+                    .as_ref()
+                    .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
                 if let Some(ref s) = cfg.android_ndk {
                     target.ndk = Some(config.src.join(s));
                 }
@@ -1328,6 +1333,14 @@ impl Config {
         self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
     }
 
+    pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind {
+        self.target_config
+            .get(&target)
+            .and_then(|t| t.llvm_libunwind)
+            .or(self.llvm_libunwind_default)
+            .unwrap_or(LlvmLibunwind::No)
+    }
+
     pub fn submodules(&self, rust_info: &GitInfo) -> bool {
         self.submodules.unwrap_or(rust_info.is_git())
     }
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 769382525fb..591f9a1ca50 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -720,7 +720,7 @@ impl Build {
     fn std_features(&self, target: TargetSelection) -> String {
         let mut features = "panic-unwind".to_string();
 
-        match self.config.llvm_libunwind {
+        match self.config.llvm_libunwind(target) {
             LlvmLibunwind::InTree => features.push_str(" llvm-libunwind"),
             LlvmLibunwind::System => features.push_str(" system-llvm-libunwind"),
             LlvmLibunwind::No => {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
new file mode 100644
index 00000000000..4cd86fecd7e
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
@@ -0,0 +1,39 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/dependence_lint.rs:13:32
+   |
+LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
+   |                                ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: generic parameters may not be used in const operations
+  --> $DIR/dependence_lint.rs:20:37
+   |
+LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
+   |                                     ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+warning: cannot use constants which depend on generic parameters in types
+  --> $DIR/dependence_lint.rs:9:9
+   |
+LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
+
+warning: cannot use constants which depend on generic parameters in types
+  --> $DIR/dependence_lint.rs:16:9
+   |
+LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
+
+error: aborting due to 2 previous errors; 2 warnings emitted
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
new file mode 100644
index 00000000000..b13bcdb2c47
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
@@ -0,0 +1,34 @@
+error: overly complex generic constant
+  --> $DIR/dependence_lint.rs:16:9
+   |
+LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
+   |
+   = help: consider moving this anonymous constant into a `const` function
+
+error: overly complex generic constant
+  --> $DIR/dependence_lint.rs:20:17
+   |
+LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
+   |
+   = help: consider moving this anonymous constant into a `const` function
+
+error: unconstrained generic constant
+  --> $DIR/dependence_lint.rs:13:12
+   |
+LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); size_of::<*mut T>()]:`
+
+error: unconstrained generic constant
+  --> $DIR/dependence_lint.rs:9:9
+   |
+LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); size_of::<*mut T>()]:`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs
new file mode 100644
index 00000000000..dcdfd75def9
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/dependence_lint.rs
@@ -0,0 +1,25 @@
+// revisions: full gce
+
+#![cfg_attr(gce, feature(generic_const_exprs))]
+#![allow(incomplete_features)]
+
+use std::mem::size_of;
+
+fn foo<T>() {
+    [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
+    //[gce]~^ ERROR unconstrained
+    //[full]~^^ WARNING cannot use constants
+    //[full]~| WARNING this was previously accepted
+    let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
+    //[full]~^ ERROR generic parameters may not be used
+    //[gce]~^^ ERROR unconstrained generic
+    [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
+    //[gce]~^ ERROR overly complex
+    //[full]~^^ WARNING cannot use constants
+    //[full]~| WARNING this was previously accepted
+    let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
+    //[full]~^ ERROR generic parameters may not be used
+    //[gce]~^^ ERROR overly complex
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/no_dependence.rs b/src/test/ui/const-generics/generic_const_exprs/no_dependence.rs
new file mode 100644
index 00000000000..db8dc6ed443
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/no_dependence.rs
@@ -0,0 +1,13 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn two_args<const N: usize, const M: usize>() -> [u8; M + 2] {
+    [0; M + 2]
+}
+
+fn yay<const N: usize>() -> [u8; 4] {
+     two_args::<N, 2>() // no lint
+}
+
+fn main() {}
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 98fd13553c0..3ffd35ecdb8 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -1,8 +1,9 @@
 // run-pass
 // needs-unwind
 // ignore-wasm32-bare compiled with panic=abort by default
-// revisions: mir thir
+// revisions: mir thir strict
 // [thir]compile-flags: -Zthir-unsafeck
+// [strict]compile-flags: -Zstrict-init-checks
 // ignore-tidy-linelength
 
 // This test checks panic emitted from `mem::{uninitialized,zeroed}`.
@@ -54,6 +55,8 @@ enum LR_NonZero {
     Right(num::NonZeroI64),
 }
 
+struct ZeroSized;
+
 fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
     let err = panic::catch_unwind(op).err();
     assert_eq!(
@@ -228,11 +231,40 @@ fn main() {
         let _val = mem::zeroed::<[!; 0]>();
         let _val = mem::uninitialized::<MaybeUninit<bool>>();
         let _val = mem::uninitialized::<[!; 0]>();
+        let _val = mem::uninitialized::<()>();
+        let _val = mem::uninitialized::<ZeroSized>();
+
+        if cfg!(strict) {
+            test_panic_msg(
+                || mem::uninitialized::<i32>(),
+                "attempted to leave type `i32` uninitialized, which is invalid"
+            );
+
+            test_panic_msg(
+                || mem::uninitialized::<*const ()>(),
+                "attempted to leave type `*const ()` uninitialized, which is invalid"
+            );
+
+            test_panic_msg(
+                || mem::uninitialized::<[i32; 1]>(),
+                "attempted to leave type `[i32; 1]` uninitialized, which is invalid"
+            );
+
+            test_panic_msg(
+                || mem::zeroed::<NonNull<()>>(),
+                "attempted to zero-initialize type `core::ptr::non_null::NonNull<()>`, which is invalid"
+            );
 
-        // These are UB because they have not been officially blessed, but we await the resolution
-        // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
-        // anything about that.
-        let _val = mem::uninitialized::<i32>();
-        let _val = mem::uninitialized::<*const ()>();
+            test_panic_msg(
+                || mem::zeroed::<[NonNull<()>; 1]>(),
+                "attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
+            );
+        } else {
+            // These are UB because they have not been officially blessed, but we await the resolution
+            // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
+            // anything about that.
+            let _val = mem::uninitialized::<i32>();
+            let _val = mem::uninitialized::<*const ()>();
+        }
     }
 }