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 @@ enum Mismatch<'a> { } _ => 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 @@ fn suggest_accessing_field_where_appropriate( .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 @@ fn suggest_as_ref_where_appropriate( | (_, 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 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result } p!( - write("{}", if first { " " } else { "+" }), + write("{}", if first { " " } else { " + " }), print(trait_ref.print_only_trait_path()) ); @@ -699,7 +699,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result } 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 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result } 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 @@ pub fn to_radians(self) -> 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 @@ pub fn max(self, other: f32) -> 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 @@ pub fn min(self, other: f32) -> 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 @@ pub fn to_radians(self) -> 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 @@ pub fn max(self, other: f64) -> 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 @@ pub fn min(self, other: f64) -> 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 @@ fn max() { 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 @@ -19,6 +19,18 @@ fn test_max_nan() { assert_eq!(2.0f32.max(f32::NAN), 2.0); } +#[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; 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 `::Associated == ()` accepts_trait(returns_opaque_foo()); - //~^ ERROR type mismatch resolving `::Associated == ()` + //~^ ERROR type mismatch resolving `::Associated == ()` accepts_trait(returns_opaque_derived_foo()); - //~^ ERROR type mismatch resolving `::Associated == ()` + //~^ ERROR type mismatch resolving `::Associated == ()` accepts_generic_trait(returns_opaque_generic()); //~^ ERROR type mismatch resolving ` as GenericTrait<()>>::Associated == ()` accepts_generic_trait(returns_opaque_generic_foo()); - //~^ ERROR type mismatch resolving `+Foo as GenericTrait<()>>::Associated == ()` + //~^ ERROR type mismatch resolving ` + Foo as GenericTrait<()>>::Associated == ()` accepts_generic_trait(returns_opaque_generic_duplicate()); - //~^ ERROR type mismatch resolving `+GenericTrait as GenericTrait<()>>::Associated == ()` + //~^ ERROR type mismatch resolving ` + GenericTrait 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 `::A LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static { | +++++++++++++++++ -error[E0271]: type mismatch resolving `::Associated == ()` +error[E0271]: type mismatch resolving `::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 `::Associated` + found associated type `::Associated` note: required by a bound in `accepts_trait` --> $DIR/issue-87261.rs:43:27 | LL | fn accepts_trait>(_: T) {} | ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait` -help: consider constraining the associated type `::Associated` to `()` +help: consider constraining the associated type `::Associated` to `()` | LL | fn returns_opaque_foo() -> impl Trait + Foo { | +++++++++++++++++ -error[E0271]: type mismatch resolving `::Associated == ()` +error[E0271]: type mismatch resolving `::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 `::Associated` - = help: consider constraining the associated type `::Associated` to `()` + found associated type `::Associated` + = help: consider constraining the associated type `::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 ` as Gener LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static { | +++++++++++++++++ -error[E0271]: type mismatch resolving `+Foo as GenericTrait<()>>::Associated == ()` +error[E0271]: type mismatch resolving ` + 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 `+Foo as GenericTrait<()>>::Associated` + found associated type ` + 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) {} | ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait` -help: consider constraining the associated type `+Foo as GenericTrait<()>>::Associated` to `()` +help: consider constraining the associated type ` + Foo as GenericTrait<()>>::Associated` to `()` | LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo { | +++++++++++++++++ -error[E0271]: type mismatch resolving `+GenericTrait as GenericTrait<()>>::Associated == ()` +error[E0271]: type mismatch resolving ` + GenericTrait as GenericTrait<()>>::Associated == ()` --> $DIR/issue-87261.rs:97:5 | LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait { @@ -252,8 +252,8 @@ LL | accepts_generic_trait(returns_opaque_generic_duplicate()); | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type | = note: expected unit type `()` - found associated type `+GenericTrait as GenericTrait<()>>::Associated` - = help: consider constraining the associated type `+GenericTrait as GenericTrait<()>>::Associated` to `()` + found associated type ` + GenericTrait as GenericTrait<()>>::Associated` + = help: consider constraining the associated type ` + GenericTrait 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` + | +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::ret_type llvm::cast(Y *) [X = llvm::GlobalValue, Y = llvm::Value]: +// Assertion `isa(Val) && "cast() 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 + } +}