about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs2
-rw-r--r--compiler/rustc_errors/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs57
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs8
-rw-r--r--library/core/src/net/ip_addr.rs154
-rw-r--r--library/core/src/ptr/const_ptr.rs2
-rw-r--r--library/std/src/process.rs10
-rw-r--r--library/std/src/sys/uefi/args.rs158
-rw-r--r--library/std/src/sys/uefi/helpers.rs7
-rw-r--r--library/std/src/sys/uefi/mod.rs1
-rw-r--r--library/std/src/thread/local.rs6
-rw-r--r--src/doc/rustc/src/platform-support/unknown-uefi.md2
-rw-r--r--tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs61
-rw-r--r--tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr98
-rw-r--r--tests/ui/pattern/issue-115599.rs7
-rw-r--r--tests/ui/pattern/issue-115599.stderr11
-rw-r--r--tests/ui/traits/new-solver/specialization-unconstrained.stderr12
-rw-r--r--triagebot.toml2
-rwxr-xr-xx9
21 files changed, 589 insertions, 32 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 8040cb22855..d23682596fd 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -18,3 +18,5 @@ b39a1d6f1a30ba29f25d7141038b9a5bf0126e36
 f97fddab91fbf290ea5b691fe355d6f915220b6e
 # format let-else
 cc907f80b95c6ec530c5ee1b05b044a468f07eca
+# format let-chains
+b2d2184edea578109a48ec3d8decbee5948e8f35
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index c2af7f38d70..da74ee6391a 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -507,6 +507,7 @@ pub enum StashKey {
     CallAssocMethod,
     TraitMissingMethod,
     OpaqueHiddenTypeMismatch,
+    MaybeForgetReturn,
 }
 
 fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index e1a0c47fc12..6e0e02b7814 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -564,7 +564,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if !errors.is_empty() {
             self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
+            let errors_causecode = errors
+                .iter()
+                .map(|e| (e.obligation.cause.span, e.root_obligation.cause.code().clone()))
+                .collect::<Vec<_>>();
             self.err_ctxt().report_fulfillment_errors(errors);
+            self.collect_unused_stmts_for_coerce_return_ty(errors_causecode);
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 5c7d64b471d..9f1800b45c3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -11,7 +11,7 @@ use crate::{
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan,
+    pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -27,6 +27,7 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::TypeTrace;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_middle::traits::ObligationCauseCode::ExprBindingObligation;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
@@ -1375,7 +1376,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 _ => bug!("unexpected type: {:?}", ty.normalized),
             },
-            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            Res::Def(
+                DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
+                _,
+            )
             | Res::SelfTyParam { .. }
             | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
                 Some(adt) if !adt.is_enum() => {
@@ -1845,6 +1849,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    pub(super) fn collect_unused_stmts_for_coerce_return_ty(
+        &self,
+        errors_causecode: Vec<(Span, ObligationCauseCode<'tcx>)>,
+    ) {
+        for (span, code) in errors_causecode {
+            let Some(mut diag) =
+                self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::MaybeForgetReturn)
+            else {
+                continue;
+            };
+
+            if let Some(fn_sig) = self.body_fn_sig()
+                && let ExprBindingObligation(_, _, hir_id, ..) = code
+                && !fn_sig.output().is_unit()
+            {
+                    let mut block_num = 0;
+                    let mut found_semi = false;
+                    for (_, node) in self.tcx.hir().parent_iter(hir_id) {
+                        match node {
+                            hir::Node::Stmt(stmt) => if let hir::StmtKind::Semi(ref expr) = stmt.kind {
+                                let expr_ty = self.typeck_results.borrow().expr_ty(expr);
+                                let return_ty = fn_sig.output();
+                                if !matches!(expr.kind, hir::ExprKind::Ret(..)) &&
+                                    self.can_coerce(expr_ty, return_ty) {
+                                    found_semi = true;
+                                }
+                            },
+                            hir::Node::Block(_block) => if found_semi {
+                                block_num += 1;
+                            }
+                            hir::Node::Item(item) => if let hir::ItemKind::Fn(..) = item.kind {
+                                break;
+                            }
+                            _ => {}
+                        }
+                    }
+                    if block_num > 1 && found_semi {
+                        diag.span_suggestion_verbose(
+                            span.shrink_to_lo(),
+                            "you might have meant to return this to infer its type parameters",
+                            "return ",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+            }
+            diag.emit();
+        }
+    }
+
     /// Given a vector of fulfillment errors, try to adjust the spans of the
     /// errors to more accurately point at the cause of the failure.
     ///
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index b7818fe57d1..fc03f7891a8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -198,6 +198,14 @@ impl<'tcx> ConstToPat<'tcx> {
                     // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                     let kind = PatKind::Error(e);
                     return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
+                } else if let ty::Adt(..) = cv.ty().kind() && matches!(cv, mir::Const::Val(..)) {
+                    // This branch is only entered when the current `cv` is `mir::Const::Val`.
+                    // This is because `mir::Const::ty` has already been handled by `Self::recur`
+                    // and the invalid types may be ignored.
+                    let err = TypeNotStructural { span: self.span, non_sm_ty };
+                    let e = self.tcx().sess.emit_err(err);
+                    let kind = PatKind::Error(e);
+                    return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
                 } else if !self.saw_const_match_lint.get() {
                     if let Some(mir_structural_match_violation) = mir_structural_match_violation {
                         match non_sm_ty.kind() {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 29d8b056c07..1020144a01b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -17,7 +17,7 @@ use crate::traits::{
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-    MultiSpan, Style,
+    MultiSpan, StashKey, Style,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, Res};
@@ -2049,14 +2049,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 // begin with in those cases.
                 if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
                     if let None = self.tainted_by_errors() {
-                        self.emit_inference_failure_err(
+                        let err = self.emit_inference_failure_err(
                             obligation.cause.body_id,
                             span,
                             trait_ref.self_ty().skip_binder().into(),
                             ErrorCode::E0282,
                             false,
-                        )
-                        .emit();
+                        );
+                        err.stash(span, StashKey::MaybeForgetReturn);
                     }
                     return;
                 }
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 6a36dfec098..b7eca9b168a 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -1,6 +1,8 @@
 use crate::cmp::Ordering;
 use crate::fmt::{self, Write};
+use crate::iter;
 use crate::mem::transmute;
+use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
 
 use super::display_buffer::DisplayBuffer;
 
@@ -410,9 +412,12 @@ impl IpAddr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ip)]
     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
     ///
+    /// let localhost_v4 = Ipv4Addr::new(127, 0, 0, 1);
+    ///
+    /// assert_eq!(IpAddr::V4(localhost_v4).to_canonical(), localhost_v4);
+    /// assert_eq!(IpAddr::V6(localhost_v4.to_ipv6_mapped()).to_canonical(), localhost_v4);
     /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
@@ -420,11 +425,11 @@ impl IpAddr {
     #[inline]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
-    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
+    #[stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")]
     pub const fn to_canonical(&self) -> IpAddr {
         match self {
-            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V4(_) => *self,
             IpAddr::V6(v6) => v6.to_canonical(),
         }
     }
@@ -1748,11 +1753,11 @@ impl Ipv6Addr {
     ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
     /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")]
+    #[inline]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
-    #[inline]
+    #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")]
+    #[rustc_const_stable(feature = "const_ipv6_to_ipv4_mapped", since = "CURRENT_RUSTC_VERSION")]
     pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
         match self.octets() {
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
@@ -1817,11 +1822,11 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
     /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
+    #[inline]
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
-    #[inline]
+    #[stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")]
     pub const fn to_canonical(&self) -> IpAddr {
         if let Some(mapped) = self.to_ipv4_mapped() {
             return IpAddr::V4(mapped);
@@ -2122,3 +2127,132 @@ impl From<[u16; 8]> for IpAddr {
         IpAddr::V6(Ipv6Addr::from(segments))
     }
 }
+
+#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+impl Not for Ipv4Addr {
+    type Output = Ipv4Addr;
+
+    #[inline]
+    fn not(mut self) -> Ipv4Addr {
+        for octet in &mut self.octets {
+            *octet = !*octet;
+        }
+        self
+    }
+}
+
+#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+impl Not for &'_ Ipv4Addr {
+    type Output = Ipv4Addr;
+
+    #[inline]
+    fn not(self) -> Ipv4Addr {
+        !*self
+    }
+}
+
+#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+impl Not for Ipv6Addr {
+    type Output = Ipv6Addr;
+
+    #[inline]
+    fn not(mut self) -> Ipv6Addr {
+        for octet in &mut self.octets {
+            *octet = !*octet;
+        }
+        self
+    }
+}
+
+#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+impl Not for &'_ Ipv6Addr {
+    type Output = Ipv6Addr;
+
+    #[inline]
+    fn not(self) -> Ipv6Addr {
+        !*self
+    }
+}
+
+macro_rules! bitop_impls {
+    ($(
+        $(#[$attr:meta])*
+        impl ($BitOp:ident, $BitOpAssign:ident) for $ty:ty = ($bitop:ident, $bitop_assign:ident);
+    )*) => {
+        $(
+            $(#[$attr])*
+            impl $BitOpAssign for $ty {
+                fn $bitop_assign(&mut self, rhs: $ty) {
+                    for (lhs, rhs) in iter::zip(&mut self.octets, rhs.octets) {
+                        lhs.$bitop_assign(rhs);
+                    }
+                }
+            }
+
+            $(#[$attr])*
+            impl $BitOpAssign<&'_ $ty> for $ty {
+                fn $bitop_assign(&mut self, rhs: &'_ $ty) {
+                    self.$bitop_assign(*rhs);
+                }
+            }
+
+            $(#[$attr])*
+            impl $BitOp for $ty {
+                type Output = $ty;
+
+                #[inline]
+                fn $bitop(mut self, rhs: $ty) -> $ty {
+                    self.$bitop_assign(rhs);
+                    self
+                }
+            }
+
+            $(#[$attr])*
+            impl $BitOp<&'_ $ty> for $ty {
+                type Output = $ty;
+
+                #[inline]
+                fn $bitop(mut self, rhs: &'_ $ty) -> $ty {
+                    self.$bitop_assign(*rhs);
+                    self
+                }
+            }
+
+            $(#[$attr])*
+            impl $BitOp<$ty> for &'_ $ty {
+                type Output = $ty;
+
+                #[inline]
+                fn $bitop(self, rhs: $ty) -> $ty {
+                    let mut lhs = *self;
+                    lhs.$bitop_assign(rhs);
+                    lhs
+                }
+            }
+
+            $(#[$attr])*
+            impl $BitOp<&'_ $ty> for &'_ $ty {
+                type Output = $ty;
+
+                #[inline]
+                fn $bitop(self, rhs: &'_ $ty) -> $ty {
+                    let mut lhs = *self;
+                    lhs.$bitop_assign(*rhs);
+                    lhs
+                }
+            }
+        )*
+    };
+}
+
+bitop_impls! {
+    #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+    impl (BitAnd, BitAndAssign) for Ipv4Addr = (bitand, bitand_assign);
+    #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+    impl (BitOr, BitOrAssign) for Ipv4Addr = (bitor, bitor_assign);
+
+    #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+    impl (BitAnd, BitAndAssign) for Ipv6Addr = (bitand, bitand_assign);
+    #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")]
+    impl (BitOr, BitOrAssign) for Ipv6Addr = (bitor, bitor_assign);
+}
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 9af8f1228f0..a3e4f0fb90a 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -842,7 +842,7 @@ impl<T: ?Sized> *const T {
     where
         T: Sized,
     {
-        match intrinsics::ptr_guaranteed_cmp(self as _, other as _) {
+        match intrinsics::ptr_guaranteed_cmp(self, other) {
             2 => None,
             other => Some(other == 1),
         }
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 47e28c27a83..ad29eeb6a0b 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1594,7 +1594,7 @@ impl From<io::Stderr> for Stdio {
 pub struct ExitStatus(imp::ExitStatus);
 
 /// The default value is one which indicates successful completion.
-#[stable(feature = "process-exitcode-default", since = "1.73.0")]
+#[stable(feature = "process_exitstatus_default", since = "1.73.0")]
 impl Default for ExitStatus {
     fn default() -> Self {
         // Ideally this would be done by ExitCode::default().into() but that is complicated.
@@ -1960,6 +1960,14 @@ impl ExitCode {
     }
 }
 
+/// The default value is [`ExitCode::SUCCESS`]
+#[stable(feature = "process_exitcode_default", since = "CURRENT_RUSTC_VERSION")]
+impl Default for ExitCode {
+    fn default() -> Self {
+        ExitCode::SUCCESS
+    }
+}
+
 #[stable(feature = "process_exitcode", since = "1.61.0")]
 impl From<u8> for ExitCode {
     /// Construct an `ExitCode` from an arbitrary u8 value.
diff --git a/library/std/src/sys/uefi/args.rs b/library/std/src/sys/uefi/args.rs
new file mode 100644
index 00000000000..4ff7be748e9
--- /dev/null
+++ b/library/std/src/sys/uefi/args.rs
@@ -0,0 +1,158 @@
+use r_efi::protocols::loaded_image;
+
+use crate::env::current_exe;
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::iter::Iterator;
+use crate::mem::size_of;
+use crate::sys::uefi::helpers;
+use crate::vec;
+
+pub struct Args {
+    parsed_args_list: vec::IntoIter<OsString>,
+}
+
+pub fn args() -> Args {
+    let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]);
+
+    // Each loaded image has an image handle that supports `EFI_LOADED_IMAGE_PROTOCOL`. Thus, this
+    // will never fail.
+    let protocol =
+        helpers::image_handle_protocol::<loaded_image::Protocol>(loaded_image::PROTOCOL_GUID)
+            .unwrap();
+
+    let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize;
+    // Break if we are sure that it cannot be UTF-16
+    if lp_size < size_of::<u16>() || lp_size % size_of::<u16>() != 0 {
+        return Args { parsed_args_list: lazy_current_exe().into_iter() };
+    }
+    let lp_size = lp_size / size_of::<u16>();
+
+    let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 };
+    if !lp_cmd_line.is_aligned() {
+        return Args { parsed_args_list: lazy_current_exe().into_iter() };
+    }
+    let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) };
+
+    Args {
+        parsed_args_list: parse_lp_cmd_line(lp_cmd_line)
+            .unwrap_or_else(lazy_current_exe)
+            .into_iter(),
+    }
+}
+
+impl fmt::Debug for Args {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.parsed_args_list.as_slice().fmt(f)
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+
+    fn next(&mut self) -> Option<OsString> {
+        self.parsed_args_list.next()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.parsed_args_list.size_hint()
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize {
+        self.parsed_args_list.len()
+    }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        self.parsed_args_list.next_back()
+    }
+}
+
+/// Implements the UEFI command-line argument parsing algorithm.
+///
+/// This implementation is based on what is defined in Section 3.4 of
+/// [UEFI Shell Specification](https://uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf)
+///
+/// Return None in the following cases:
+/// - Invalid UTF-16 (unpaired surrogate)
+/// - Empty/improper arguments
+fn parse_lp_cmd_line(code_units: &[u16]) -> Option<Vec<OsString>> {
+    const QUOTE: char = '"';
+    const SPACE: char = ' ';
+    const CARET: char = '^';
+    const NULL: char = '\0';
+
+    let mut ret_val = Vec::new();
+    let mut code_units_iter = char::decode_utf16(code_units.iter().cloned()).peekable();
+
+    // The executable name at the beginning is special.
+    let mut in_quotes = false;
+    let mut cur = String::new();
+    while let Some(w) = code_units_iter.next() {
+        let w = w.ok()?;
+        match w {
+            // break on NULL
+            NULL => break,
+            // A quote mark always toggles `in_quotes` no matter what because
+            // there are no escape characters when parsing the executable name.
+            QUOTE => in_quotes = !in_quotes,
+            // If not `in_quotes` then whitespace ends argv[0].
+            SPACE if !in_quotes => break,
+            // In all other cases the code unit is taken literally.
+            _ => cur.push(w),
+        }
+    }
+
+    // If exe name is missing, the cli args are invalid
+    if cur.is_empty() {
+        return None;
+    }
+
+    ret_val.push(OsString::from(cur));
+    // Skip whitespace.
+    while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {}
+
+    // Parse the arguments according to these rules:
+    // * All code units are taken literally except space, quote and caret.
+    // * When not `in_quotes`, space separate arguments. Consecutive spaces are
+    // treated as a single separator.
+    // * A space `in_quotes` is taken literally.
+    // * A quote toggles `in_quotes` mode unless it's escaped. An escaped quote is taken literally.
+    // * A quote can be escaped if preceded by caret.
+    // * A caret can be escaped if preceded by caret.
+    let mut cur = String::new();
+    let mut in_quotes = false;
+    while let Some(w) = code_units_iter.next() {
+        let w = w.ok()?;
+        match w {
+            // break on NULL
+            NULL => break,
+            // If not `in_quotes`, a space or tab ends the argument.
+            SPACE if !in_quotes => {
+                ret_val.push(OsString::from(&cur[..]));
+                cur.truncate(0);
+
+                // Skip whitespace.
+                while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {}
+            }
+            // Caret can escape quotes or carets
+            CARET if in_quotes => {
+                if let Some(x) = code_units_iter.next() {
+                    cur.push(x.ok()?);
+                }
+            }
+            // If quote then flip `in_quotes`
+            QUOTE => in_quotes = !in_quotes,
+            // Everything else is always taken literally.
+            _ => cur.push(w),
+        }
+    }
+    // Push the final argument, if any.
+    if !cur.is_empty() || in_quotes {
+        ret_val.push(OsString::from(cur));
+    }
+    Some(ret_val)
+}
diff --git a/library/std/src/sys/uefi/helpers.rs b/library/std/src/sys/uefi/helpers.rs
index 126661bfc96..9837cc89f2d 100644
--- a/library/std/src/sys/uefi/helpers.rs
+++ b/library/std/src/sys/uefi/helpers.rs
@@ -139,3 +139,10 @@ pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result
 
     if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
 }
+
+/// Get the Protocol for current system handle.
+/// Note: Some protocols need to be manually freed. It is the callers responsibility to do so.
+pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> Option<NonNull<T>> {
+    let system_handle = uefi::env::try_image_handle()?;
+    open_protocol(system_handle, protocol_guid).ok()
+}
diff --git a/library/std/src/sys/uefi/mod.rs b/library/std/src/sys/uefi/mod.rs
index 097396ae993..4edc00e3ea0 100644
--- a/library/std/src/sys/uefi/mod.rs
+++ b/library/std/src/sys/uefi/mod.rs
@@ -13,7 +13,6 @@
 //! [`OsString`]: crate::ffi::OsString
 
 pub mod alloc;
-#[path = "../unsupported/args.rs"]
 pub mod args;
 #[path = "../unix/cmath.rs"]
 pub mod cmath;
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 09994e47f0a..def94acd457 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -29,9 +29,9 @@ use crate::fmt;
 /// within a thread, and values that implement [`Drop`] get destructed when a
 /// thread exits. Some caveats apply, which are explained below.
 ///
-/// A `LocalKey`'s initializer cannot recursively depend on itself, and using
-/// a `LocalKey` in this way will cause the initializer to infinitely recurse
-/// on the first call to `with`.
+/// A `LocalKey`'s initializer cannot recursively depend on itself. Using a
+/// `LocalKey` in this way may cause panics, aborts or infinite recursion on
+/// the first call to `with`.
 ///
 /// # Examples
 ///
diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md
index 370939520dc..1230ea22bd9 100644
--- a/src/doc/rustc/src/platform-support/unknown-uefi.md
+++ b/src/doc/rustc/src/platform-support/unknown-uefi.md
@@ -268,6 +268,8 @@ cargo build --target x86_64-unknown-uefi -Zbuild-std=std,panic_abort
 #### stdio
 - Uses `Simple Text Input Protocol` and `Simple Text Output Protocol`.
 - Note: UEFI uses CRLF for new line. This means Enter key is registered as CR instead of LF.
+#### args
+- Uses `EFI_LOADED_IMAGE_PROTOCOL->LoadOptions`
 
 ## Example: Hello World With std
 The following code features a valid UEFI application, including `stdio` and `alloc` (`OsString` and `Vec`):
diff --git a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs
new file mode 100644
index 00000000000..4544c898ab8
--- /dev/null
+++ b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs
@@ -0,0 +1,61 @@
+struct MyError;
+
+fn foo(x: bool) -> Result<(), MyError> {
+    if x {
+        Err(MyError);
+        //~^ ERROR type annotations needed
+    }
+
+    Ok(())
+}
+
+fn bar(x: bool) -> Result<(), MyError> {
+    if x {
+        Ok(());
+        //~^ ERROR type annotations needed
+    }
+
+    Ok(())
+}
+
+fn baz(x: bool) -> Result<(), MyError> {
+    //~^ ERROR mismatched types
+    if x {
+        1;
+    }
+
+    Err(MyError);
+}
+
+fn error() -> Result<(), MyError> {
+    Err(MyError)
+}
+
+fn bak(x: bool) -> Result<(), MyError> {
+    if x {
+        //~^ ERROR mismatched types
+        error();
+    } else {
+        //~^ ERROR mismatched types
+        error();
+    }
+}
+
+fn bad(x: bool) -> Result<(), MyError> {
+    Err(MyError); //~ ERROR type annotations needed
+    Ok(())
+}
+
+fn with_closure<F, A, B>(_: F) -> i32
+where
+    F: FnOnce(A, B),
+{
+    0
+}
+
+fn a() -> i32 {
+    with_closure(|x: u32, y| {}); //~ ERROR type annotations needed
+    0
+}
+
+fn main() {}
diff --git a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr
new file mode 100644
index 00000000000..1fea73529a8
--- /dev/null
+++ b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr
@@ -0,0 +1,98 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:5:9
+   |
+LL |         Err(MyError);
+   |         ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         Err::<T, MyError>(MyError);
+   |            ++++++++++++++
+help: you might have meant to return this to infer its type parameters
+   |
+LL |         return Err(MyError);
+   |         ++++++
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:14:9
+   |
+LL |         Ok(());
+   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         Ok::<(), E>(());
+   |           +++++++++
+help: you might have meant to return this to infer its type parameters
+   |
+LL |         return Ok(());
+   |         ++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:21:20
+   |
+LL | fn baz(x: bool) -> Result<(), MyError> {
+   |    ---             ^^^^^^^^^^^^^^^^^^^ expected `Result<(), MyError>`, found `()`
+   |    |
+   |    implicitly returns `()` as its body has no tail or `return` expression
+...
+LL |     Err(MyError);
+   |                 - help: remove this semicolon to return this value
+   |
+   = note:   expected enum `Result<(), MyError>`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:35:10
+   |
+LL |       if x {
+   |  __________^
+LL | |
+LL | |         error();
+   | |                - help: remove this semicolon to return this value
+LL | |     } else {
+   | |_____^ expected `Result<(), MyError>`, found `()`
+   |
+   = note:   expected enum `Result<(), MyError>`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:38:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |
+LL | |         error();
+   | |                - help: remove this semicolon to return this value
+LL | |     }
+   | |_____^ expected `Result<(), MyError>`, found `()`
+   |
+   = note:   expected enum `Result<(), MyError>`
+           found unit type `()`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:45:5
+   |
+LL |     Err(MyError);
+   |     ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     Err::<T, MyError>(MyError);
+   |        ++++++++++++++
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:57:27
+   |
+LL |     with_closure(|x: u32, y| {});
+   |                           ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     with_closure(|x: u32, y: /* Type */| {});
+   |                            ++++++++++++
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0282, E0308.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/pattern/issue-115599.rs b/tests/ui/pattern/issue-115599.rs
new file mode 100644
index 00000000000..7a222b90aec
--- /dev/null
+++ b/tests/ui/pattern/issue-115599.rs
@@ -0,0 +1,7 @@
+const CONST_STRING: String = String::new();
+
+fn main() {
+    let empty_str = String::from("");
+    if let CONST_STRING = empty_str {}
+    //~^ ERROR to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]`
+}
diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr
new file mode 100644
index 00000000000..e6cb6c1ddac
--- /dev/null
+++ b/tests/ui/pattern/issue-115599.stderr
@@ -0,0 +1,11 @@
+error: to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/issue-115599.rs:5:12
+   |
+LL |     if let CONST_STRING = empty_str {}
+   |            ^^^^^^^^^^^^
+   |
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+
+error: aborting due to previous error
+
diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.stderr b/tests/ui/traits/new-solver/specialization-unconstrained.stderr
index 9915da1a27a..ed4dafa1484 100644
--- a/tests/ui/traits/new-solver/specialization-unconstrained.stderr
+++ b/tests/ui/traits/new-solver/specialization-unconstrained.stderr
@@ -8,12 +8,6 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0282]: type annotations needed
-  --> $DIR/specialization-unconstrained.rs:14:22
-   |
-LL |    default type Id = T;
-   |                      ^ cannot infer type for associated type `<T as Default>::Id`
-
 error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id == ()`
   --> $DIR/specialization-unconstrained.rs:20:5
    |
@@ -26,6 +20,12 @@ note: required by a bound in `test`
 LL | fn test<T: Default<Id = U>, U>() {}
    |                    ^^^^^^ required by this bound in `test`
 
+error[E0282]: type annotations needed
+  --> $DIR/specialization-unconstrained.rs:14:22
+   |
+LL |    default type Id = T;
+   |                      ^ cannot infer type for associated type `<T as Default>::Id`
+
 error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0282, E0284.
diff --git a/triagebot.toml b/triagebot.toml
index e60a61a63ea..036a53b5e49 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -734,7 +734,7 @@ style-team = [
 "/compiler/rustc_traits" =                   ["compiler", "types"]
 "/compiler/rustc_type_ir" =                  ["compiler", "types"]
 "/library/alloc" =                           ["libs"]
-"/library/core" =                            ["libs", "@scottmcm"]
+"/library/core" =                            ["libs"]
 "/library/panic_abort" =                     ["libs"]
 "/library/panic_unwind" =                    ["libs"]
 "/library/proc_macro" =                      ["@petrochenkov"]
diff --git a/x b/x
index ef3eb8b04b4..426b58d0d4e 100755
--- a/x
+++ b/x
@@ -11,10 +11,13 @@ set -eu
 sh -n "$0"
 
 realpath() {
-    if [ -d "$1" ]; then
-        CDPATH='' command cd "$1" && pwd -P
+    local path="$1"
+    if [ -L "$path" ]; then
+        readlink -f "$path"
+    elif [ -d "$path" ]; then
+        (cd -P "$path" && pwd)
     else
-        echo "$(realpath "$(dirname "$1")")/$(basename "$1")"
+        echo "$(realpath "$(dirname "$path")")/$(basename "$path")"
     fi
 }