about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-06 16:12:13 +0000
committerbors <bors@rust-lang.org>2020-11-06 16:12:13 +0000
commit7e9a36fa8a4ec06daec581e23f390389e05f25e4 (patch)
treeafe67d3f71142bcd9766b5f6480c994017da6519 /compiler
parentdc06a36074f04c6a77b5834f2950011d49607898 (diff)
parentaf50c796faaf68adf01eb16afe86f368a64cc906 (diff)
downloadrust-7e9a36fa8a4ec06daec581e23f390389e05f25e4.tar.gz
rust-7e9a36fa8a4ec06daec581e23f390389e05f25e4.zip
Auto merge of #78810 - JohnTitor:rollup-8fhtvxu, r=JohnTitor
Rollup of 15 pull requests

Successful merges:

 - #74979 (`#![deny(unsafe_op_in_unsafe_fn)]` in sys/hermit)
 - #78006 (Use Intra-doc links for std::io::buffered)
 - #78167 (Fix unreachable sub-branch detection in or-patterns)
 - #78514 (Allow using 1/2/3/4 for `x.py setup` options)
 - #78538 (BTreeMap: document a curious assumption in test cases)
 - #78559 (Add LLVM upgrades from 7 to 10 to RELEASES.md)
 - #78666 (Fix shellcheck error)
 - #78705 (Print a summary of which test suite failed)
 - #78726 (Add link to rust website)
 - #78730 (Expand explanation of reverse_bits)
 - #78760 (`deny(invalid_codeblock_attributes)` for rustc_error_codes)
 - #78771 (inliner: Copy unevaluated constants only after successful inlining)
 - #78794 (rustc_expand: use collect_bang helper instead of manual reimplementation)
 - #78795 (The renumber pass is long gone)
 - #78798 (Fixing Spelling Typos)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/node_id.rs4
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/cargo.sh4
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/config.sh1
-rwxr-xr-xcompiler/rustc_codegen_cranelift/test.sh4
-rw-r--r--compiler/rustc_error_codes/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/expand.rs6
-rw-r--r--compiler/rustc_mir/src/transform/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/_match.rs120
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs7
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs2
11 files changed, 116 insertions, 53 deletions
diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs
index 1035e945538..6e7d2bab287 100644
--- a/compiler/rustc_ast/src/node_id.rs
+++ b/compiler/rustc_ast/src/node_id.rs
@@ -13,8 +13,8 @@ rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeId);
 pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0);
 
 /// When parsing and doing expansions, we initially give all AST nodes this AST
-/// node value. Then later, in the renumber pass, we renumber them to have
-/// small, positive ids.
+/// node value. Then later, during expansion, we renumber them to have small,
+/// positive ids.
 pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
 
 impl NodeId {
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.sh b/compiler/rustc_codegen_cranelift/scripts/cargo.sh
index e63daa40f35..947b4a28798 100755
--- a/compiler/rustc_codegen_cranelift/scripts/cargo.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo.sh
@@ -10,7 +10,7 @@ cmd=$1
 shift || true
 
 if [[ "$cmd" = "jit" ]]; then
-cargo +${TOOLCHAIN} rustc $@ -- --jit
+cargo +${TOOLCHAIN} rustc "$@" -- --jit
 else
-cargo +${TOOLCHAIN} $cmd $@
+cargo +${TOOLCHAIN} $cmd "$@"
 fi
diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh
index af181f4f724..6120a550a27 100644
--- a/compiler/rustc_codegen_cranelift/scripts/config.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/config.sh
@@ -1,3 +1,4 @@
+#!/usr/bin/env bash
 set -e
 
 unamestr=`uname`
diff --git a/compiler/rustc_codegen_cranelift/test.sh b/compiler/rustc_codegen_cranelift/test.sh
index 3cdd4119d79..c6c4956e481 100755
--- a/compiler/rustc_codegen_cranelift/test.sh
+++ b/compiler/rustc_codegen_cranelift/test.sh
@@ -3,13 +3,13 @@ set -e
 
 export RUSTFLAGS="-Zrun_dsymutil=no"
 
-./build.sh --without-sysroot $@
+./build.sh --without-sysroot "$@"
 
 rm -r target/out || true
 
 scripts/tests.sh no_sysroot
 
-./build.sh $@
+./build.sh "$@"
 
 scripts/tests.sh base_sysroot
 scripts/tests.sh extended_sysroot
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 4353a294cc3..e4a70253144 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -1,3 +1,4 @@
+#![deny(invalid_codeblock_attributes)]
 //! This library is used to gather all error codes into one place,
 //! the goal being to make their maintenance easier.
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 3e5762ab992..f6959591b56 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1436,9 +1436,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 item.attrs = attrs;
                 self.check_attributes(&item.attrs);
                 item.and_then(|item| match item.kind {
-                    ItemKind::MacCall(mac) => self
-                        .collect(AstFragmentKind::Items, InvocationKind::Bang { mac, span })
-                        .make_items(),
+                    ItemKind::MacCall(mac) => {
+                        self.collect_bang(mac, span, AstFragmentKind::Items).make_items()
+                    }
                     _ => unreachable!(),
                 })
             }
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index 3d68b862df2..acec3e8f82f 100644
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ b/compiler/rustc_mir/src/transform/check_unsafety.rs
@@ -693,7 +693,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                 // should only issue a warning for the sake of backwards compatibility.
                 //
                 // The solution those 2 expectations is to always take the minimum of both lints.
-                // This prevent any new errors (unless both lints are explicitely set to `deny`).
+                // This prevent any new errors (unless both lints are explicitly set to `deny`).
                 let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0
                     <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0
                 {
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index 5407226e386..4de93739992 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -140,14 +140,6 @@ impl Inliner<'tcx> {
                 continue;
             };
 
-            // Copy only unevaluated constants from the callee_body into the caller_body.
-            // Although we are only pushing `ConstKind::Unevaluated` consts to
-            // `required_consts`, here we may not only have `ConstKind::Unevaluated`
-            // because we are calling `subst_and_normalize_erasing_regions`.
-            caller_body.required_consts.extend(callee_body.required_consts.iter().copied().filter(
-                |&constant| matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _)),
-            ));
-
             let start = caller_body.basic_blocks().len();
             debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body);
             if !self.inline_call(callsite, caller_body, callee_body) {
@@ -522,6 +514,16 @@ impl Inliner<'tcx> {
                     kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
                 });
 
+                // Copy only unevaluated constants from the callee_body into the caller_body.
+                // Although we are only pushing `ConstKind::Unevaluated` consts to
+                // `required_consts`, here we may not only have `ConstKind::Unevaluated`
+                // because we are calling `subst_and_normalize_erasing_regions`.
+                caller_body.required_consts.extend(
+                    callee_body.required_consts.iter().copied().filter(|&constant| {
+                        matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _))
+                    }),
+                );
+
                 true
             }
             kind => {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index bc85d45d867..5e7e81eba62 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -1,5 +1,11 @@
-//! Note: most of the tests relevant to this file can be found (at the time of writing) in
-//! src/tests/ui/pattern/usefulness.
+//! Note: tests specific to this file can be found in:
+//!     - ui/pattern/usefulness
+//!     - ui/or-patterns
+//!     - ui/consts/const_in_pattern
+//!     - ui/rfc-2008-non-exhaustive
+//!     - probably many others
+//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
+//! reason not to, for example if they depend on a particular feature like or_patterns.
 //!
 //! This file includes the logic for exhaustiveness and usefulness checking for
 //! pattern-matching. Specifically, given a list of patterns for a type, we can
@@ -1361,8 +1367,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
 
 #[derive(Clone, Debug)]
 crate enum Usefulness<'tcx> {
-    /// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
-    Useful(Vec<Span>),
+    /// Carries, for each column in the matrix, a set of sub-branches that have been found to be
+    /// unreachable. Used only in the presence of or-patterns, otherwise it stays empty.
+    Useful(Vec<FxHashSet<Span>>),
     /// Carries a list of witnesses of non-exhaustiveness.
     UsefulWithWitness(Vec<Witness<'tcx>>),
     NotUseful,
@@ -1410,6 +1417,23 @@ impl<'tcx> Usefulness<'tcx> {
                 };
                 UsefulWithWitness(new_witnesses)
             }
+            Useful(mut unreachables) => {
+                if !unreachables.is_empty() {
+                    // When we apply a constructor, there are `arity` columns of the matrix that
+                    // corresponded to its arguments. All the unreachables found in these columns
+                    // will, after `apply`, come from the first column. So we take the union of all
+                    // the corresponding sets and put them in the first column.
+                    // Note that `arity` may be 0, in which case we just push a new empty set.
+                    let len = unreachables.len();
+                    let arity = ctor_wild_subpatterns.len();
+                    let mut unioned = FxHashSet::default();
+                    for set in unreachables.drain((len - arity)..) {
+                        unioned.extend(set)
+                    }
+                    unreachables.push(unioned);
+                }
+                Useful(unreachables)
+            }
             x => x,
         }
     }
@@ -2091,13 +2115,14 @@ crate fn is_useful<'p, 'tcx>(
 
     // If the first pattern is an or-pattern, expand it.
     if let Some(vs) = v.expand_or_pat() {
-        // We need to push the already-seen patterns into the matrix in order to detect redundant
-        // branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
-        let mut matrix = matrix.clone();
-        // `Vec` of all the unreachable branches of the current or-pattern.
-        let mut unreachable_branches = Vec::new();
-        // Subpatterns that are unreachable from all branches. E.g. in the following case, the last
-        // `true` is unreachable only from one branch, so it is overall reachable.
+        // We expand the or pattern, trying each of its branches in turn and keeping careful track
+        // of possible unreachable sub-branches.
+        //
+        // If two branches have detected some unreachable sub-branches, we need to be careful. If
+        // they were detected in columns that are not the current one, we want to keep only the
+        // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last
+        // `true` is unreachable in the second branch of the first or-pattern, but not otherwise.
+        // Therefore we don't want to lint that it is unreachable.
         //
         // ```
         // match (true, true) {
@@ -2105,41 +2130,72 @@ crate fn is_useful<'p, 'tcx>(
         //     (false | true, false | true) => {}
         // }
         // ```
-        let mut unreachable_subpats = FxHashSet::default();
-        // Whether any branch at all is useful.
+        // If however the sub-branches come from the current column, they come from the inside of
+        // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want
+        // to lint that the last `false` is unreachable.
+        // ```
+        // match None {
+        //     Some(false) => {}
+        //     None | Some(true | false) => {}
+        // }
+        // ```
+
+        let mut matrix = matrix.clone();
+        // We keep track of sub-branches separately depending on whether they come from this column
+        // or from others.
+        let mut unreachables_this_column: FxHashSet<Span> = FxHashSet::default();
+        let mut unreachables_other_columns: Vec<FxHashSet<Span>> = Vec::default();
+        // Whether at least one branch is reachable.
         let mut any_is_useful = false;
 
         for v in vs {
             let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
             match res {
-                Useful(pats) => {
-                    if !any_is_useful {
-                        any_is_useful = true;
-                        // Initialize with the first set of unreachable subpatterns encountered.
-                        unreachable_subpats = pats.into_iter().collect();
-                    } else {
-                        // Keep the patterns unreachable from both this and previous branches.
-                        unreachable_subpats =
-                            pats.into_iter().filter(|p| unreachable_subpats.contains(p)).collect();
+                Useful(unreachables) => {
+                    if let Some((this_column, other_columns)) = unreachables.split_last() {
+                        // We keep the union of unreachables found in the first column.
+                        unreachables_this_column.extend(this_column);
+                        // We keep the intersection of unreachables found in other columns.
+                        if unreachables_other_columns.is_empty() {
+                            unreachables_other_columns = other_columns.to_vec();
+                        } else {
+                            unreachables_other_columns = unreachables_other_columns
+                                .into_iter()
+                                .zip(other_columns)
+                                .map(|(x, y)| x.intersection(&y).copied().collect())
+                                .collect();
+                        }
                     }
+                    any_is_useful = true;
                 }
-                NotUseful => unreachable_branches.push(v.head().span),
-                UsefulWithWitness(_) => {
-                    bug!("Encountered or-pat in `v` during exhaustiveness checking")
+                NotUseful => {
+                    unreachables_this_column.insert(v.head().span);
                 }
+                UsefulWithWitness(_) => bug!(
+                    "encountered or-pat in the expansion of `_` during exhaustiveness checking"
+                ),
             }
-            // If pattern has a guard don't add it to the matrix
+
+            // If pattern has a guard don't add it to the matrix.
             if !is_under_guard {
+                // We push the already-seen patterns into the matrix in order to detect redundant
+                // branches like `Some(_) | Some(0)`.
                 matrix.push(v);
             }
         }
-        if any_is_useful {
-            // Collect all the unreachable patterns.
-            unreachable_branches.extend(unreachable_subpats);
-            return Useful(unreachable_branches);
+
+        return if any_is_useful {
+            let mut unreachables = if unreachables_other_columns.is_empty() {
+                let n_columns = v.len();
+                (0..n_columns - 1).map(|_| FxHashSet::default()).collect()
+            } else {
+                unreachables_other_columns
+            };
+            unreachables.push(unreachables_this_column);
+            Useful(unreachables)
         } else {
-            return NotUseful;
-        }
+            NotUseful
+        };
     }
 
     // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 30b700a1d4f..205ad850c0c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -389,8 +389,11 @@ fn check_arms<'p, 'tcx>(
                     hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
                 }
             }
-            Useful(unreachable_subpatterns) => {
-                for span in unreachable_subpatterns {
+            Useful(unreachables) => {
+                let mut unreachables: Vec<_> = unreachables.into_iter().flatten().collect();
+                // Emit lints in the order in which they occur in the file.
+                unreachables.sort_unstable();
+                for span in unreachables {
                     unreachable_pattern(cx.tcx, span, id, None);
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 53bc2069b76..f76f42dea1e 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1500,7 +1500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.span_suggestion(
             sp,
             &format!(
-                "if you don't care about {} missing field{}, you can explicitely ignore {}",
+                "if you don't care about {} missing field{}, you can explicitly ignore {}",
                 if len == 1 { "this" } else { "these" },
                 if len == 1 { "" } else { "s" },
                 if len == 1 { "it" } else { "them" },