about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-11-21 10:19:33 +0000
committerbors <bors@rust-lang.org>2021-11-21 10:19:33 +0000
commit3bfde2f1f4fc9409ecb63dfe1370df66171cf861 (patch)
treeed9e0b4780c7980749b09d4fd1ea9b57202c709a
parentb8e5ab20ed7a7677a998a163ccf7853764b195e6 (diff)
parenta54eae94a019a4128265413f3799b8d93a81c2e3 (diff)
downloadrust-3bfde2f1f4fc9409ecb63dfe1370df66171cf861.tar.gz
rust-3bfde2f1f4fc9409ecb63dfe1370df66171cf861.zip
Auto merge of #91104 - matthiaskrgr:rollup-duk33o1, r=matthiaskrgr
Rollup of 4 pull requests

Successful merges:

 - #91008 (Adds IEEE 754-2019 minimun and maximum functions for f32/f64)
 - #91070 (Make `LLVMRustGetOrInsertGlobal` always return a `GlobalVariable`)
 - #91097 (Add spaces in opaque `impl Trait` with more than one trait)
 - #91098 (Don't suggest certain fixups (`.field`, `.await`, etc) when reporting errors while matching on arrays )

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs24
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp12
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--library/core/src/num/f32.rs68
-rw-r--r--library/core/src/num/f64.rs68
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/num/mod.rs61
-rw-r--r--library/std/src/f32/tests.rs12
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--src/test/ui/associated-types/issue-87261.rs8
-rw-r--r--src/test/ui/associated-types/issue-87261.stderr24
-rw-r--r--src/test/ui/cast/casts-differing-anon.stderr2
-rw-r--r--src/test/ui/issues/issue-5358-1.stderr4
-rw-r--r--src/test/ui/match/issue-91058.rs11
-rw-r--r--src/test/ui/match/issue-91058.stderr11
-rw-r--r--src/test/ui/statics/issue-91050-1.rs34
-rw-r--r--src/test/ui/statics/issue-91050-2.rs24
17 files changed, 344 insertions, 27 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index a85892f1b5e..85226e60bdb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1695,11 +1695,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
             _ => exp_found,
         };
-        debug!("exp_found {:?} terr {:?}", exp_found, terr);
+        debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code);
         if let Some(exp_found) = exp_found {
-            self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
-            self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
-            self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
+            let should_suggest_fixes = if let ObligationCauseCode::Pattern { root_ty, .. } =
+                &cause.code
+            {
+                // Skip if the root_ty of the pattern is not the same as the expected_ty.
+                // If these types aren't equal then we've probably peeled off a layer of arrays.
+                same_type_modulo_infer(self.resolve_vars_if_possible(*root_ty), exp_found.expected)
+            } else {
+                true
+            };
+
+            if should_suggest_fixes {
+                self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
+                self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
+                self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
+            }
         }
 
         // In some (most?) cases cause.body_id points to actual body, but in some cases
@@ -1879,7 +1891,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 .iter()
                 .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
                 .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
-                .find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
+                .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
             {
                 if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -1944,7 +1956,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                         | (_, ty::Infer(_))
                                         | (ty::Param(_), _)
                                         | (ty::Infer(_), _) => {}
-                                        _ if ty::TyS::same_type(exp_ty, found_ty) => {}
+                                        _ if same_type_modulo_infer(exp_ty, found_ty) => {}
                                         _ => show_suggestion = false,
                                     };
                                 }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index e77d29bed71..f3d8eb2602a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -124,8 +124,18 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
 
 extern "C" LLVMValueRef
 LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) {
+  Module *Mod = unwrap(M);
   StringRef NameRef(Name, NameLen);
-  return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty)));
+
+  // We don't use Module::getOrInsertGlobal because that returns a Constant*,
+  // which may either be the real GlobalVariable*, or a constant bitcast of it
+  // if our type doesn't match the original declaration. We always want the
+  // GlobalVariable* so we can access linkage, visibility, etc.
+  GlobalVariable *GV = Mod->getGlobalVariable(NameRef, true);
+  if (!GV)
+    GV = new GlobalVariable(*Mod, unwrap(Ty), false,
+                            GlobalValue::ExternalLinkage, nullptr, NameRef);
+  return wrap(GV);
 }
 
 extern "C" LLVMValueRef
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index c8e898c6849..3846cf19d91 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -688,7 +688,7 @@ pub trait PrettyPrinter<'tcx>:
                                 }
 
                                 p!(
-                                    write("{}", if first { " " } else { "+" }),
+                                    write("{}", if first { " " } else { " + " }),
                                     print(trait_ref.print_only_trait_path())
                                 );
 
@@ -699,7 +699,7 @@ pub trait PrettyPrinter<'tcx>:
                     }
 
                     if is_future {
-                        p!(write("{}Future", if first { " " } else { "+" }));
+                        p!(write("{}Future", if first { " " } else { " + " }));
                         first = false;
 
                         if let Some(future_output_ty) = future_output_ty {
@@ -712,7 +712,7 @@ pub trait PrettyPrinter<'tcx>:
                     }
 
                     if !is_sized {
-                        p!(write("{}?Sized", if first { " " } else { "+" }));
+                        p!(write("{}?Sized", if first { " " } else { " + " }));
                     } else if first {
                         p!(" Sized");
                     }
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 905b0c42458..c4a232ef36c 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -673,6 +673,9 @@ impl f32 {
 
     /// Returns the maximum of the two numbers.
     ///
+    /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
+    /// This matches the behavior of libm’s fmin.
+    ///
     /// ```
     /// let x = 1.0f32;
     /// let y = 2.0f32;
@@ -689,6 +692,9 @@ impl f32 {
 
     /// Returns the minimum of the two numbers.
     ///
+    /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs.
+    /// This matches the behavior of libm’s fmin.
+    ///
     /// ```
     /// let x = 1.0f32;
     /// let y = 2.0f32;
@@ -703,6 +709,68 @@ impl f32 {
         intrinsics::minnumf32(self, other)
     }
 
+    /// Returns the maximum of the two numbers, propagating NaNs.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f32::max`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(float_minimum_maximum)]
+    /// let x = 1.0f32;
+    /// let y = 2.0f32;
+    ///
+    /// assert_eq!(x.maximum(y), y);
+    /// assert!(x.maximum(f32::NAN).is_nan());
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[inline]
+    pub fn maximum(self, other: f32) -> f32 {
+        if self > other {
+            self
+        } else if other > self {
+            other
+        } else if self == other {
+            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+        } else {
+            self + other
+        }
+    }
+
+    /// Returns the minimum of the two numbers, propagating NaNs.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f32::min`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(float_minimum_maximum)]
+    /// let x = 1.0f32;
+    /// let y = 2.0f32;
+    ///
+    /// assert_eq!(x.minimum(y), x);
+    /// assert!(x.minimum(f32::NAN).is_nan());
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[inline]
+    pub fn minimum(self, other: f32) -> f32 {
+        if self < other {
+            self
+        } else if other < self {
+            other
+        } else if self == other {
+            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+        } else {
+            self + other
+        }
+    }
+
     /// Rounds toward zero and converts to any primitive integer type,
     /// assuming that the value is finite and fits in that type.
     ///
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 112a239a145..85ee6aa2cb8 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -689,6 +689,9 @@ impl f64 {
 
     /// Returns the maximum of the two numbers.
     ///
+    /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
+    /// This matches the behavior of libm’s fmin.
+    ///
     /// ```
     /// let x = 1.0_f64;
     /// let y = 2.0_f64;
@@ -705,6 +708,9 @@ impl f64 {
 
     /// Returns the minimum of the two numbers.
     ///
+    /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs.
+    /// This matches the behavior of libm’s fmin.
+    ///
     /// ```
     /// let x = 1.0_f64;
     /// let y = 2.0_f64;
@@ -719,6 +725,68 @@ impl f64 {
         intrinsics::minnumf64(self, other)
     }
 
+    /// Returns the maximum of the two numbers, propagating NaNs.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f64::max`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(float_minimum_maximum)]
+    /// let x = 1.0_f64;
+    /// let y = 2.0_f64;
+    ///
+    /// assert_eq!(x.maximum(y), y);
+    /// assert!(x.maximum(f64::NAN).is_nan());
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[inline]
+    pub fn maximum(self, other: f64) -> f64 {
+        if self > other {
+            self
+        } else if other > self {
+            other
+        } else if self == other {
+            if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
+        } else {
+            self + other
+        }
+    }
+
+    /// Returns the minimum of the two numbers, propagating NaNs.
+    ///
+    /// This returns NaN when *either* argument is NaN, as opposed to
+    /// [`f64::min`] which only returns NaN when *both* arguments are NaN.
+    ///
+    /// ```
+    /// #![feature(float_minimum_maximum)]
+    /// let x = 1.0_f64;
+    /// let y = 2.0_f64;
+    ///
+    /// assert_eq!(x.minimum(y), x);
+    /// assert!(x.minimum(f64::NAN).is_nan());
+    /// ```
+    ///
+    /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
+    /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
+    /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[unstable(feature = "float_minimum_maximum", issue = "91079")]
+    #[inline]
+    pub fn minimum(self, other: f64) -> f64 {
+        if self < other {
+            self
+        } else if other < self {
+            other
+        } else if self == other {
+            if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
+        } else {
+            self + other
+        }
+    }
+
     /// Rounds toward zero and converts to any primitive integer type,
     /// assuming that the value is finite and fits in that type.
     ///
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index b9acd0d2990..a56a1dbd17a 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -27,6 +27,7 @@
 #![feature(extern_types)]
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
+#![feature(float_minimum_maximum)]
 #![feature(array_from_fn)]
 #![feature(hashmap_internals)]
 #![feature(try_find)]
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 37b5e9127d5..4f773a824ef 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -715,6 +715,67 @@ macro_rules! test_float {
                 assert!(($nan as $fty).max($nan).is_nan());
             }
             #[test]
+            fn minimum() {
+                assert_eq!((0.0 as $fty).minimum(0.0), 0.0);
+                assert!((0.0 as $fty).minimum(0.0).is_sign_positive());
+                assert_eq!((-0.0 as $fty).minimum(0.0), -0.0);
+                assert!((-0.0 as $fty).minimum(0.0).is_sign_negative());
+                assert_eq!((-0.0 as $fty).minimum(-0.0), -0.0);
+                assert!((-0.0 as $fty).minimum(-0.0).is_sign_negative());
+                assert_eq!((9.0 as $fty).minimum(9.0), 9.0);
+                assert_eq!((-9.0 as $fty).minimum(0.0), -9.0);
+                assert_eq!((0.0 as $fty).minimum(9.0), 0.0);
+                assert!((0.0 as $fty).minimum(9.0).is_sign_positive());
+                assert_eq!((-0.0 as $fty).minimum(9.0), -0.0);
+                assert!((-0.0 as $fty).minimum(9.0).is_sign_negative());
+                assert_eq!((-0.0 as $fty).minimum(-9.0), -9.0);
+                assert_eq!(($inf as $fty).minimum(9.0), 9.0);
+                assert_eq!((9.0 as $fty).minimum($inf), 9.0);
+                assert_eq!(($inf as $fty).minimum(-9.0), -9.0);
+                assert_eq!((-9.0 as $fty).minimum($inf), -9.0);
+                assert_eq!(($neginf as $fty).minimum(9.0), $neginf);
+                assert_eq!((9.0 as $fty).minimum($neginf), $neginf);
+                assert_eq!(($neginf as $fty).minimum(-9.0), $neginf);
+                assert_eq!((-9.0 as $fty).minimum($neginf), $neginf);
+                assert!(($nan as $fty).minimum(9.0).is_nan());
+                assert!(($nan as $fty).minimum(-9.0).is_nan());
+                assert!((9.0 as $fty).minimum($nan).is_nan());
+                assert!((-9.0 as $fty).minimum($nan).is_nan());
+                assert!(($nan as $fty).minimum($nan).is_nan());
+            }
+            #[test]
+            fn maximum() {
+                assert_eq!((0.0 as $fty).maximum(0.0), 0.0);
+                assert!((0.0 as $fty).maximum(0.0).is_sign_positive());
+                assert_eq!((-0.0 as $fty).maximum(0.0), 0.0);
+                assert!((-0.0 as $fty).maximum(0.0).is_sign_positive());
+                assert_eq!((-0.0 as $fty).maximum(-0.0), -0.0);
+                assert!((-0.0 as $fty).maximum(-0.0).is_sign_negative());
+                assert_eq!((9.0 as $fty).maximum(9.0), 9.0);
+                assert_eq!((-9.0 as $fty).maximum(0.0), 0.0);
+                assert!((-9.0 as $fty).maximum(0.0).is_sign_positive());
+                assert_eq!((-9.0 as $fty).maximum(-0.0), -0.0);
+                assert!((-9.0 as $fty).maximum(-0.0).is_sign_negative());
+                assert_eq!((0.0 as $fty).maximum(9.0), 9.0);
+                assert_eq!((0.0 as $fty).maximum(-9.0), 0.0);
+                assert!((0.0 as $fty).maximum(-9.0).is_sign_positive());
+                assert_eq!((-0.0 as $fty).maximum(-9.0), -0.0);
+                assert!((-0.0 as $fty).maximum(-9.0).is_sign_negative());
+                assert_eq!(($inf as $fty).maximum(9.0), $inf);
+                assert_eq!((9.0 as $fty).maximum($inf), $inf);
+                assert_eq!(($inf as $fty).maximum(-9.0), $inf);
+                assert_eq!((-9.0 as $fty).maximum($inf), $inf);
+                assert_eq!(($neginf as $fty).maximum(9.0), 9.0);
+                assert_eq!((9.0 as $fty).maximum($neginf), 9.0);
+                assert_eq!(($neginf as $fty).maximum(-9.0), -9.0);
+                assert_eq!((-9.0 as $fty).maximum($neginf), -9.0);
+                assert!(($nan as $fty).maximum(9.0).is_nan());
+                assert!(($nan as $fty).maximum(-9.0).is_nan());
+                assert!((9.0 as $fty).maximum($nan).is_nan());
+                assert!((-9.0 as $fty).maximum($nan).is_nan());
+                assert!(($nan as $fty).maximum($nan).is_nan());
+            }
+            #[test]
             fn rem_euclid() {
                 let a: $fty = 42.0;
                 assert!($inf.rem_euclid(a).is_nan());
diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs
index 0d4b865f339..69fa203ff4e 100644
--- a/library/std/src/f32/tests.rs
+++ b/library/std/src/f32/tests.rs
@@ -20,6 +20,18 @@ fn test_max_nan() {
 }
 
 #[test]
+fn test_minimum() {
+    assert!(f32::NAN.minimum(2.0).is_nan());
+    assert!(2.0f32.minimum(f32::NAN).is_nan());
+}
+
+#[test]
+fn test_maximum() {
+    assert!(f32::NAN.maximum(2.0).is_nan());
+    assert!(2.0f32.maximum(f32::NAN).is_nan());
+}
+
+#[test]
 fn test_nan() {
     let nan: f32 = f32::NAN;
     assert!(nan.is_nan());
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index f2490a77ce0..afd8d8edaa1 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -287,6 +287,7 @@
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
 #![feature(fn_traits)]
+#![feature(float_minimum_maximum)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
 #![feature(generator_trait)]
diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs
index a70f771e482..384561f8ccd 100644
--- a/src/test/ui/associated-types/issue-87261.rs
+++ b/src/test/ui/associated-types/issue-87261.rs
@@ -83,17 +83,17 @@ fn main() {
     //~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
 
     accepts_trait(returns_opaque_foo());
-    //~^ ERROR type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
 
     accepts_trait(returns_opaque_derived_foo());
-    //~^ ERROR type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic());
     //~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic_foo());
-    //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
 
     accepts_generic_trait(returns_opaque_generic_duplicate());
-    //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
 }
diff --git a/src/test/ui/associated-types/issue-87261.stderr b/src/test/ui/associated-types/issue-87261.stderr
index b85d64b86ae..8db4a49da3c 100644
--- a/src/test/ui/associated-types/issue-87261.stderr
+++ b/src/test/ui/associated-types/issue-87261.stderr
@@ -160,7 +160,7 @@ help: consider constraining the associated type `<impl DerivedTrait as Trait>::A
 LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
    |                                                 +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
   --> $DIR/issue-87261.rs:85:5
    |
 LL | fn returns_opaque_foo() -> impl Trait + Foo {
@@ -170,18 +170,18 @@ LL |     accepts_trait(returns_opaque_foo());
    |     ^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl Trait+Foo as Trait>::Associated`
+           found associated type `<impl Trait + Foo as Trait>::Associated`
 note: required by a bound in `accepts_trait`
   --> $DIR/issue-87261.rs:43:27
    |
 LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
    |                           ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
-help: consider constraining the associated type `<impl Trait+Foo as Trait>::Associated` to `()`
+help: consider constraining the associated type `<impl Trait + Foo as Trait>::Associated` to `()`
    |
 LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
    |                                      +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
   --> $DIR/issue-87261.rs:88:5
    |
 LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
@@ -191,8 +191,8 @@ LL |     accepts_trait(returns_opaque_derived_foo());
    |     ^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl DerivedTrait+Foo as Trait>::Associated`
-   = help: consider constraining the associated type `<impl DerivedTrait+Foo as Trait>::Associated` to `()`
+           found associated type `<impl DerivedTrait + Foo as Trait>::Associated`
+   = help: consider constraining the associated type `<impl DerivedTrait + Foo as Trait>::Associated` to `()`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 note: required by a bound in `accepts_trait`
   --> $DIR/issue-87261.rs:43:27
@@ -221,7 +221,7 @@ help: consider constraining the associated type `<impl GenericTrait<()> as Gener
 LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
    |                                                    +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
   --> $DIR/issue-87261.rs:94:5
    |
 LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
@@ -231,18 +231,18 @@ LL |     accepts_generic_trait(returns_opaque_generic_foo());
    |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated`
+           found associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated`
 note: required by a bound in `accepts_generic_trait`
   --> $DIR/issue-87261.rs:44:46
    |
 LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
    |                                              ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait`
-help: consider constraining the associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated` to `()`
+help: consider constraining the associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated` to `()`
    |
 LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
    |                                                        +++++++++++++++++
 
-error[E0271]: type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
   --> $DIR/issue-87261.rs:97:5
    |
 LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
@@ -252,8 +252,8 @@ LL |     accepts_generic_trait(returns_opaque_generic_duplicate());
    |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
    |
    = note:    expected unit type `()`
-           found associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated`
-   = help: consider constraining the associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
+           found associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated`
+   = help: consider constraining the associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 note: required by a bound in `accepts_generic_trait`
   --> $DIR/issue-87261.rs:44:46
diff --git a/src/test/ui/cast/casts-differing-anon.stderr b/src/test/ui/cast/casts-differing-anon.stderr
index a30e9b35f5c..f9abfb5225f 100644
--- a/src/test/ui/cast/casts-differing-anon.stderr
+++ b/src/test/ui/cast/casts-differing-anon.stderr
@@ -1,4 +1,4 @@
-error[E0606]: casting `*mut impl Debug+?Sized` as `*mut impl Debug+?Sized` is invalid
+error[E0606]: casting `*mut impl Debug + ?Sized` as `*mut impl Debug + ?Sized` is invalid
   --> $DIR/casts-differing-anon.rs:21:13
    |
 LL |     b_raw = f_raw as *mut _;
diff --git a/src/test/ui/issues/issue-5358-1.stderr b/src/test/ui/issues/issue-5358-1.stderr
index 314d1fddbd7..d1bc279c758 100644
--- a/src/test/ui/issues/issue-5358-1.stderr
+++ b/src/test/ui/issues/issue-5358-1.stderr
@@ -8,6 +8,10 @@ LL |         Either::Right(_) => {}
    |
    = note: expected struct `S`
                 found enum `Either<_, _>`
+help: you might have meant to use field `0` whose type is `Either<usize, usize>`
+   |
+LL |     match S(Either::Left(5)).0 {
+   |           ~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/match/issue-91058.rs b/src/test/ui/match/issue-91058.rs
new file mode 100644
index 00000000000..4845937d544
--- /dev/null
+++ b/src/test/ui/match/issue-91058.rs
@@ -0,0 +1,11 @@
+struct S(());
+
+fn main() {
+    let array = [S(())];
+
+    match array {
+        [()] => {}
+        //~^ ERROR mismatched types [E0308]
+        _ => {}
+    }
+}
diff --git a/src/test/ui/match/issue-91058.stderr b/src/test/ui/match/issue-91058.stderr
new file mode 100644
index 00000000000..ec1d7e21fa5
--- /dev/null
+++ b/src/test/ui/match/issue-91058.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-91058.rs:7:10
+   |
+LL |     match array {
+   |           ----- this expression has type `[S; 1]`
+LL |         [()] => {}
+   |          ^^ expected struct `S`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/statics/issue-91050-1.rs b/src/test/ui/statics/issue-91050-1.rs
new file mode 100644
index 00000000000..403a41462ef
--- /dev/null
+++ b/src/test/ui/statics/issue-91050-1.rs
@@ -0,0 +1,34 @@
+// build-pass
+// compile-flags: --crate-type=rlib --emit=llvm-ir -Cno-prepopulate-passes
+
+// This test declares globals by the same name with different types, which
+// caused problems because Module::getOrInsertGlobal would return a Constant*
+// bitcast instead of a GlobalVariable* that could access linkage/visibility.
+// In alt builds with LLVM assertions this would fail:
+//
+// rustc: /checkout/src/llvm-project/llvm/include/llvm/Support/Casting.h:269:
+// typename cast_retty<X, Y *>::ret_type llvm::cast(Y *) [X = llvm::GlobalValue, Y = llvm::Value]:
+// Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
+//
+// In regular builds, the bad cast was UB, like "Invalid LLVMRustVisibility value!"
+
+pub mod before {
+    #[no_mangle]
+    pub static GLOBAL1: [u8; 1] = [1];
+}
+
+pub mod inner {
+    extern "C" {
+        pub static GLOBAL1: u8;
+        pub static GLOBAL2: u8;
+    }
+
+    pub fn call() {
+        drop(unsafe { (GLOBAL1, GLOBAL2) });
+    }
+}
+
+pub mod after {
+    #[no_mangle]
+    pub static GLOBAL2: [u8; 1] = [2];
+}
diff --git a/src/test/ui/statics/issue-91050-2.rs b/src/test/ui/statics/issue-91050-2.rs
new file mode 100644
index 00000000000..2ff954d15ca
--- /dev/null
+++ b/src/test/ui/statics/issue-91050-2.rs
@@ -0,0 +1,24 @@
+// build-pass
+// compile-flags: --crate-type=rlib --emit=llvm-ir -Cno-prepopulate-passes
+
+// This is a variant of issue-91050-1.rs -- see there for an explanation.
+
+pub mod before {
+    extern "C" {
+        pub static GLOBAL1: [u8; 1];
+    }
+
+    pub unsafe fn do_something_with_array() -> u8 {
+        GLOBAL1[0]
+    }
+}
+
+pub mod inner {
+    extern "C" {
+        pub static GLOBAL1: u8;
+    }
+
+    pub unsafe fn call() -> u8 {
+        GLOBAL1 + 42
+    }
+}