diff options
| author | bors <bors@rust-lang.org> | 2020-11-06 16:12:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-11-06 16:12:13 +0000 |
| commit | 7e9a36fa8a4ec06daec581e23f390389e05f25e4 (patch) | |
| tree | afe67d3f71142bcd9766b5f6480c994017da6519 /compiler | |
| parent | dc06a36074f04c6a77b5834f2950011d49607898 (diff) | |
| parent | af50c796faaf68adf01eb16afe86f368a64cc906 (diff) | |
| download | rust-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.rs | 4 | ||||
| -rwxr-xr-x | compiler/rustc_codegen_cranelift/scripts/cargo.sh | 4 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/scripts/config.sh | 1 | ||||
| -rwxr-xr-x | compiler/rustc_codegen_cranelift/test.sh | 4 | ||||
| -rw-r--r-- | compiler/rustc_error_codes/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/expand.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/transform/check_unsafety.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/transform/inline.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/_match.rs | 120 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/pat.rs | 2 |
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" }, |
