From 023cc968e1295994ed8039da43b0f2f4ea4e9390 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 19 Nov 2021 19:33:29 -0800 Subject: [PATCH 01/10] Make `LLVMRustGetOrInsertGlobal` always return a `GlobalVariable` `Module::getOrInsertGlobal` returns a `Constant*`, which is a super class of `GlobalVariable`, but if the given type doesn't match an existing declaration, it returns a bitcast of that global instead. This causes UB when we pass that to `LLVMGetVisibility` which unconditionally casts the opaque argument to a `GlobalValue*`. Instead, we can do our own get-or-insert without worrying whether existing types match exactly. It's not relevant when we're just trying to get/set the linkage and visibility, and if types are needed we can bitcast or error nicely from `rustc_codegen_llvm` instead. --- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 12 ++++++- src/test/ui/issues/issue-91050.rs | 34 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-91050.rs diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index e77d29bed7122..f3d8eb2602a37 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/src/test/ui/issues/issue-91050.rs b/src/test/ui/issues/issue-91050.rs new file mode 100644 index 0000000000000..50763d30931b7 --- /dev/null +++ b/src/test/ui/issues/issue-91050.rs @@ -0,0 +1,34 @@ +// build-pass +// compile-flags: --crate-type lib -Ccodegen-units=1 + +// 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]; +} From a8ee0e9c2cfa7c607e24d78c774e9e843da08e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Thu, 18 Nov 2021 11:48:52 +0100 Subject: [PATCH 02/10] Implement IEEE 754-2019 minimun and maximum functions for f32/f64 --- library/core/src/num/f32.rs | 62 +++++++++++++++++++++++++++++++++++ library/core/src/num/f64.rs | 62 +++++++++++++++++++++++++++++++++++ library/core/tests/lib.rs | 1 + library/core/tests/num/mod.rs | 61 ++++++++++++++++++++++++++++++++++ library/std/src/f32/tests.rs | 12 +++++++ library/std/src/lib.rs | 1 + 6 files changed, 199 insertions(+) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 905b0c4245801..4571df917f385 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -703,6 +703,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 follow 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 follow 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 112a239a145f6..0ae32c5ea9507 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -719,6 +719,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 follow 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 follow 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 b9acd0d29903d..a56a1dbd17ae0 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 37b5e9127d5b0..4f773a824efd2 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 0d4b865f3392a..69fa203ff4e70 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 f2490a77ce0f8..afd8d8edaa169 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)] From 2bad89390052399e4c850a2793691f3371122880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Thu, 18 Nov 2021 11:48:52 +0100 Subject: [PATCH 03/10] Add similar note as LLVM does for minNum and maxNum functions --- library/core/src/num/f32.rs | 6 ++++++ library/core/src/num/f64.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 4571df917f385..4b4711b2cba6d 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 match’s 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 match’s the behavior of libm’s fmin. + /// /// ``` /// let x = 1.0f32; /// let y = 2.0f32; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 0ae32c5ea9507..a1ca09e78f275 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 match’s 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 match’s the behavior of libm’s fmin. + /// /// ``` /// let x = 1.0_f64; /// let y = 2.0_f64; From e2ec3b1dd72357f7d91f04c14e040e6e698630fa Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 20 Nov 2021 23:05:30 +0100 Subject: [PATCH 04/10] Apply documentation suggestions from @est31 Co-authored-by: est31 --- library/core/src/num/f32.rs | 8 ++++---- library/core/src/num/f64.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 4b4711b2cba6d..c4a232ef36c61 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -674,7 +674,7 @@ impl f32 { /// Returns the maximum of the two numbers. /// /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs. - /// This match’s the behavior of libm’s fmin. + /// This matches the behavior of libm’s fmin. /// /// ``` /// let x = 1.0f32; @@ -693,7 +693,7 @@ impl f32 { /// Returns the minimum of the two numbers. /// /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs. - /// This match’s the behavior of libm’s fmin. + /// This matches the behavior of libm’s fmin. /// /// ``` /// let x = 1.0f32; @@ -725,7 +725,7 @@ impl f32 { /// /// 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 follow the semantics specified in IEEE 754-2019. + /// 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 { @@ -756,7 +756,7 @@ impl f32 { /// /// 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 follow the semantics specified in IEEE 754-2019. + /// 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 { diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index a1ca09e78f275..85ee6aa2cb8c3 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -690,7 +690,7 @@ impl f64 { /// Returns the maximum of the two numbers. /// /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs. - /// This match’s the behavior of libm’s fmin. + /// This matches the behavior of libm’s fmin. /// /// ``` /// let x = 1.0_f64; @@ -709,7 +709,7 @@ impl f64 { /// Returns the minimum of the two numbers. /// /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs. - /// This match’s the behavior of libm’s fmin. + /// This matches the behavior of libm’s fmin. /// /// ``` /// let x = 1.0_f64; @@ -741,7 +741,7 @@ impl f64 { /// /// 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 follow the semantics specified in IEEE 754-2019. + /// 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 { @@ -772,7 +772,7 @@ impl f64 { /// /// 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 follow the semantics specified in IEEE 754-2019. + /// 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 { From 3b2cfa574699d3d92c1114837e347dd7ee248fcb Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 20 Nov 2021 16:29:15 -0800 Subject: [PATCH 05/10] Add another test variant of issue-91050 Co-authored-by: Simonas Kazlauskas --- .../{issue-91050.rs => issue-91050-1.rs} | 2 +- src/test/ui/issues/issue-91050-2.rs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) rename src/test/ui/issues/{issue-91050.rs => issue-91050-1.rs} (92%) create mode 100644 src/test/ui/issues/issue-91050-2.rs diff --git a/src/test/ui/issues/issue-91050.rs b/src/test/ui/issues/issue-91050-1.rs similarity index 92% rename from src/test/ui/issues/issue-91050.rs rename to src/test/ui/issues/issue-91050-1.rs index 50763d30931b7..403a41462ef18 100644 --- a/src/test/ui/issues/issue-91050.rs +++ b/src/test/ui/issues/issue-91050-1.rs @@ -1,5 +1,5 @@ // build-pass -// compile-flags: --crate-type lib -Ccodegen-units=1 +// 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* diff --git a/src/test/ui/issues/issue-91050-2.rs b/src/test/ui/issues/issue-91050-2.rs new file mode 100644 index 0000000000000..2ff954d15cabe --- /dev/null +++ b/src/test/ui/issues/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 + } +} From 3aa1954b0bfc3f10917d5ff8fa315ac3cae5c45a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 20 Nov 2021 17:02:37 -0800 Subject: [PATCH 06/10] Move the issue-91050 tests to appease tidy --- src/test/ui/{issues => statics}/issue-91050-1.rs | 0 src/test/ui/{issues => statics}/issue-91050-2.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{issues => statics}/issue-91050-1.rs (100%) rename src/test/ui/{issues => statics}/issue-91050-2.rs (100%) diff --git a/src/test/ui/issues/issue-91050-1.rs b/src/test/ui/statics/issue-91050-1.rs similarity index 100% rename from src/test/ui/issues/issue-91050-1.rs rename to src/test/ui/statics/issue-91050-1.rs diff --git a/src/test/ui/issues/issue-91050-2.rs b/src/test/ui/statics/issue-91050-2.rs similarity index 100% rename from src/test/ui/issues/issue-91050-2.rs rename to src/test/ui/statics/issue-91050-2.rs From 8805e934afbcc2549dfa328e328bc7f4350b7059 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 20 Nov 2021 17:01:47 -0800 Subject: [PATCH 07/10] Add space in opaque `impl Trait` --- compiler/rustc_middle/src/ty/print/pretty.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c8e898c684957..3846cf19d915b 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"); } From d99b132586435e62423e00f2e0c0eed9106f0ca8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 20 Nov 2021 17:07:42 -0800 Subject: [PATCH 08/10] Fixup test outputs --- src/test/ui/associated-types/issue-87261.rs | 8 +++---- .../ui/associated-types/issue-87261.stderr | 24 +++++++++---------- src/test/ui/cast/casts-differing-anon.stderr | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs index a70f771e4826f..384561f8ccd7e 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 b85d64b86ae66..8db4a49da3c96 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 a30e9b35f5cf6..f9abfb5225f91 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 _; From 3ba27e7dfa69b5a9e1b8c5ff8868ed822dcff344 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 19 Nov 2021 15:22:44 -0800 Subject: [PATCH 09/10] Use same_type_modulo_infer in more places --- .../rustc_infer/src/infer/error_reporting/mod.rs | 4 ++-- .../exclusive_range_pattern_syntax_collision.stderr | 4 ++++ .../exclusive_range_pattern_syntax_collision2.stderr | 4 ++++ .../exclusive_range_pattern_syntax_collision3.stderr | 12 ++++++++++++ src/test/ui/issues/issue-5358-1.stderr | 4 ++++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 3c2f990008062..640300c2d4554 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1879,7 +1879,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 +1944,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/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr index a6f8563a04785..1df7fd59f57b2 100644 --- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr @@ -8,6 +8,10 @@ LL | [_, 99.., _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` +help: you might have meant to use field `start` whose type is `{integer}` + | +LL | match [5..4, 99..105, 43..44].start { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr index 4e0102c930da8..87484c1072dd0 100644 --- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr @@ -14,6 +14,10 @@ LL | [_, 99..] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` +help: you might have meant to use field `start` whose type is `{integer}` + | +LL | match [5..4, 99..105, 43..44].start { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr index 665eef2fcb96c..c48f6cce93c2f 100644 --- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr +++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr @@ -8,6 +8,10 @@ LL | [..9, 99..100, _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` +help: you might have meant to use field `start` whose type is `{integer}` + | +LL | match [5..4, 99..105, 43..44].start { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:15 @@ -21,6 +25,10 @@ LL | [..9, 99..100, _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` +help: you might have meant to use field `start` whose type is `{integer}` + | +LL | match [5..4, 99..105, 43..44].start { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:19 @@ -34,6 +42,10 @@ LL | [..9, 99..100, _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` +help: you might have meant to use field `start` whose type is `{integer}` + | +LL | match [5..4, 99..105, 43..44].start { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-5358-1.stderr b/src/test/ui/issues/issue-5358-1.stderr index 314d1fddbd76a..d1bc279c7589a 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 From 01b24045faebc1d0d9f42f355e536df6fc693e49 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 19 Nov 2021 14:57:33 -0800 Subject: [PATCH 10/10] Fix for issue 91058 --- .../src/infer/error_reporting/mod.rs | 20 +++++++++++++++---- ...sive_range_pattern_syntax_collision.stderr | 4 ---- ...ive_range_pattern_syntax_collision2.stderr | 4 ---- ...ive_range_pattern_syntax_collision3.stderr | 12 ----------- src/test/ui/match/issue-91058.rs | 11 ++++++++++ src/test/ui/match/issue-91058.stderr | 11 ++++++++++ 6 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 src/test/ui/match/issue-91058.rs create mode 100644 src/test/ui/match/issue-91058.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 640300c2d4554..e32906b75338e 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 diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr index 1df7fd59f57b2..a6f8563a04785 100644 --- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr @@ -8,10 +8,6 @@ LL | [_, 99.., _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` -help: you might have meant to use field `start` whose type is `{integer}` - | -LL | match [5..4, 99..105, 43..44].start { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr index 87484c1072dd0..4e0102c930da8 100644 --- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr @@ -14,10 +14,6 @@ LL | [_, 99..] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` -help: you might have meant to use field `start` whose type is `{integer}` - | -LL | match [5..4, 99..105, 43..44].start { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr index c48f6cce93c2f..665eef2fcb96c 100644 --- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr +++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr @@ -8,10 +8,6 @@ LL | [..9, 99..100, _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` -help: you might have meant to use field `start` whose type is `{integer}` - | -LL | match [5..4, 99..105, 43..44].start { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:15 @@ -25,10 +21,6 @@ LL | [..9, 99..100, _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` -help: you might have meant to use field `start` whose type is `{integer}` - | -LL | match [5..4, 99..105, 43..44].start { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:19 @@ -42,10 +34,6 @@ LL | [..9, 99..100, _] => {}, | = note: expected struct `std::ops::Range<{integer}>` found type `{integer}` -help: you might have meant to use field `start` whose type is `{integer}` - | -LL | match [5..4, 99..105, 43..44].start { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 3 previous errors diff --git a/src/test/ui/match/issue-91058.rs b/src/test/ui/match/issue-91058.rs new file mode 100644 index 0000000000000..4845937d54401 --- /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 0000000000000..ec1d7e21fa53c --- /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`.