summary refs log tree commit diff
path: root/compiler/rustc_session/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-09-26 06:44:28 +0000
committerbors <bors@rust-lang.org>2020-09-26 06:44:28 +0000
commitfd15e6180d9c48b4f1157e44cdaff6e901e5f854 (patch)
tree11801a40b3c4b0ccc7c10b589347b28348705871 /compiler/rustc_session/src
parent9e1c4361780e69ed54444a3b03fef0cbbc26b547 (diff)
parentdaf976f6129e5fb16effc48bf91853548774e235 (diff)
downloadrust-fd15e6180d9c48b4f1157e44cdaff6e901e5f854.tar.gz
rust-fd15e6180d9c48b4f1157e44cdaff6e901e5f854.zip
Auto merge of #70743 - oli-obk:eager_const_to_pat_conversion, r=eddyb
Fully destructure constants into patterns

r? `@varkor`

as discussed in https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/constants.20in.20patterns/near/192789924

we should probably crater it once reviewed
Diffstat (limited to 'compiler/rustc_session/src')
-rw-r--r--compiler/rustc_session/src/lint/builtin.rs108
1 files changed, 90 insertions, 18 deletions
diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs
index 562df176b14..13a4057a35b 100644
--- a/compiler/rustc_session/src/lint/builtin.rs
+++ b/compiler/rustc_session/src/lint/builtin.rs
@@ -2138,22 +2138,16 @@ declare_lint! {
     /// ```rust,compile_fail
     /// #![deny(indirect_structural_match)]
     ///
-    /// struct Plus(i32, i32);
-    /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2);
-    ///
-    /// impl PartialEq for Plus {
-    ///     fn eq(&self, other: &Self) -> bool {
-    ///         self.0 + self.1 == other.0 + other.1
-    ///     }
-    /// }
-    ///
-    /// impl Eq for Plus {}
-    ///
+    /// struct NoDerive(i32);
+    /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+    /// impl Eq for NoDerive { }
+    /// #[derive(PartialEq, Eq)]
+    /// struct WrapParam<T>(T);
+    /// const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(NoDerive(0));
     /// fn main() {
-    ///     if let ONE_PLUS_TWO = &&Plus(3, 0) {
-    ///         println!("semantic!");
-    ///     } else {
-    ///         println!("structural!");
+    ///     match WRAP_INDIRECT_PARAM {
+    ///         WRAP_INDIRECT_PARAM => { }
+    ///         _ => { }
     ///     }
     /// }
     /// ```
@@ -2170,9 +2164,8 @@ declare_lint! {
     /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub INDIRECT_STRUCTURAL_MATCH,
-    // defaulting to allow until rust-lang/rust#62614 is fixed.
-    Allow,
-    "pattern with const indirectly referencing non-structural-match type",
+    Warn,
+    "constant used in pattern contains value of non-structural-match type in a field or a variant",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
         edition: None,
@@ -2198,6 +2191,83 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `pointer_structural_match` lint detects pointers used in patterns whose behaviour
+    /// cannot be relied upon across compiler versions and optimization levels.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(pointer_structural_match)]
+    /// fn foo(a: usize, b: usize) -> usize { a + b }
+    /// const FOO: fn(usize, usize) -> usize = foo;
+    /// fn main() {
+    ///     match FOO {
+    ///         FOO => {},
+    ///         _ => {},
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previous versions of Rust allowed function pointers and wide raw pointers in patterns.
+    /// While these work in many cases as expected by users, it is possible that due to
+    /// optimizations pointers are "not equal to themselves" or pointers to different functions
+    /// compare as equal during runtime. This is because LLVM optimizations can deduplicate
+    /// functions if their bodies are the same, thus also making pointers to these functions point
+    /// to the same location. Additionally functions may get duplicated if they are instantiated
+    /// in different crates and not deduplicated again via LTO.
+    pub POINTER_STRUCTURAL_MATCH,
+    Allow,
+    "pointers are not structural-match",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/70861>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    /// The `nontrivial_structural_match` lint detects constants that are used in patterns,
+    /// whose type is not structural-match and whose initializer body actually uses values
+    /// that are not structural-match. So `Option<NotStruturalMatch>` is ok if the constant
+    /// is just `None`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(nontrivial_structural_match)]
+    ///
+    /// #[derive(Copy, Clone, Debug)]
+    /// struct NoDerive(u32);
+    /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+    /// impl Eq for NoDerive { }
+    /// fn main() {
+    ///     const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
+    ///     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previous versions of Rust accepted constants in patterns, even if those constants's types
+    /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of
+    /// `PartialEq`, which can report that two constants are not equal even if they are
+    /// bit-equivalent.
+    pub NONTRIVIAL_STRUCTURAL_MATCH,
+    Warn,
+    "constant used in pattern of non-structural-match type and the constant's initializer \
+    expression contains values of non-structural-match types",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #73448 <https://github.com/rust-lang/rust/issues/73448>",
+        edition: None,
+    };
+}
+
+declare_lint! {
     /// The `ambiguous_associated_items` lint detects ambiguity between
     /// [associated items] and [enum variants].
     ///
@@ -2630,6 +2700,8 @@ declare_lint_pass! {
         AMBIGUOUS_ASSOCIATED_ITEMS,
         MUTABLE_BORROW_RESERVATION_CONFLICT,
         INDIRECT_STRUCTURAL_MATCH,
+        POINTER_STRUCTURAL_MATCH,
+        NONTRIVIAL_STRUCTURAL_MATCH,
         SOFT_UNSTABLE,
         INLINE_NO_SANITIZE,
         ASM_SUB_REGISTER,