]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #66318 - mati865:llvm-update, r=matthewjasper
authorbors <bors@rust-lang.org>
Tue, 12 Nov 2019 12:55:02 +0000 (12:55 +0000)
committerbors <bors@rust-lang.org>
Tue, 12 Nov 2019 12:55:02 +0000 (12:55 +0000)
Update LLVM submodule

Fixes https://github.com/rust-lang/rust/issues/66315

57 files changed:
Cargo.lock
src/bootstrap/flags.rs
src/doc/rustdoc/src/SUMMARY.md
src/doc/rustdoc/src/how-to-write-documentation.md [new file with mode: 0644]
src/doc/rustdoc/src/lints.md [new file with mode: 0644]
src/libcore/num/mod.rs
src/librustc/middle/stability.rs
src/librustc/session/code_stats.rs
src/librustc/session/mod.rs
src/librustc/ty/layout.rs
src/librustc_driver/lib.rs
src/librustc_errors/lib.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/hair/pattern/check_match.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_target/spec/windows_base.rs
src/librustc_typeck/error_codes.rs
src/librustdoc/clean/mod.rs
src/libstd/collections/hash/set.rs
src/libsyntax/ast.rs
src/libsyntax/attr/builtin.rs
src/libsyntax/feature_gate/active.rs
src/libsyntax/feature_gate/check.rs
src/libsyntax/feature_gate/mod.rs
src/libsyntax/token.rs
src/libsyntax/tokenstream.rs
src/libsyntax_ext/proc_macro_harness.rs
src/test/ui/consts/const_let_refutable.stderr
src/test/ui/feature-gate/unstable-attribute-allow-issue-none.rs [new file with mode: 0644]
src/test/ui/feature-gate/unstable-attribute-allow-issue-none.stderr [new file with mode: 0644]
src/test/ui/pattern/slice-pattern-const-2.rs [deleted file]
src/test/ui/pattern/slice-pattern-const-2.stderr [deleted file]
src/test/ui/pattern/slice-pattern-const-3.rs [deleted file]
src/test/ui/pattern/slice-pattern-const-3.stderr [deleted file]
src/test/ui/pattern/slice-pattern-const.rs [deleted file]
src/test/ui/pattern/slice-pattern-const.stderr [deleted file]
src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
src/test/ui/pattern/usefulness/match-slice-patterns.rs
src/test/ui/pattern/usefulness/match-slice-patterns.stderr
src/test/ui/pattern/usefulness/non-exhaustive-match.rs
src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
src/test/ui/pattern/usefulness/slice-pattern-const-2.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-pattern-const-3.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-pattern-const.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-pattern-const.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-patterns-reachability.rs [new file with mode: 0644]
src/test/ui/pattern/usefulness/slice-patterns-reachability.stderr [new file with mode: 0644]
src/test/ui/proc-macro/exports.stderr
src/test/ui/proc-macro/pub-at-crate-root.rs
src/test/ui/proc-macro/pub-at-crate-root.stderr
src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
src/tools/clippy

index 08155c51d97e738e09c4cc4d9f8d894b550546a2..16f2ffc28150f6c8507c4779df227c32315e0afd 100644 (file)
@@ -2252,9 +2252,9 @@ dependencies = [
 
 [[package]]
 name = "openssl"
-version = "0.10.16"
+version = "0.10.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9"
+checksum = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -2281,15 +2281,15 @@ dependencies = [
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.43"
+version = "0.9.52"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d"
+checksum = "c977d08e1312e2f7e4b86f9ebaa0ed3b19d1daff75fae88bbb88108afbd801fc"
 dependencies = [
+ "autocfg",
  "cc",
  "libc",
  "openssl-src",
  "pkg-config",
- "rustc_version",
  "vcpkg",
 ]
 
index d9580b598155edc946002b2a77efa6ad0d73ad7f..7b49cc0a9298cc059b56e2c2670e214bf78c02a5 100644 (file)
@@ -448,12 +448,12 @@ pub fn parse(args: &[String]) -> Flags {
 
         Flags {
             verbose: matches.opt_count("verbose"),
-            stage: matches.opt_str("stage").map(|j| j.parse().unwrap()),
+            stage: matches.opt_str("stage").map(|j| j.parse().expect("`stage` should be a number")),
             dry_run: matches.opt_present("dry-run"),
             on_fail: matches.opt_str("on-fail"),
             rustc_error_format: matches.opt_str("error-format"),
             keep_stage: matches.opt_strs("keep-stage")
-                .into_iter().map(|j| j.parse().unwrap())
+                .into_iter().map(|j| j.parse().expect("`keep-stage` should be a number"))
                 .collect(),
             host: split(&matches.opt_strs("host"))
                 .into_iter()
@@ -464,7 +464,7 @@ pub fn parse(args: &[String]) -> Flags {
                 .map(|x| INTERNER.intern_string(x))
                 .collect::<Vec<_>>(),
             config: cfg_file,
-            jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
+            jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
             cmd,
             incremental: matches.opt_present("incremental"),
             exclude: split(&matches.opt_strs("exclude"))
index 46528187c11754eecbf2be1e59434bb2a3acaec5..d4202f5b367ab4686a8b13b009efaf4475b21c26 100644 (file)
@@ -1,8 +1,10 @@
 # The Rustdoc Book
 
 - [What is rustdoc?](what-is-rustdoc.md)
+- [How to write documentation](how-to-write-documentation.md)
 - [Command-line arguments](command-line-arguments.md)
 - [The `#[doc]` attribute](the-doc-attribute.md)
 - [Documentation tests](documentation-tests.md)
+- [Lints](lints.md)
 - [Passes](passes.md)
 - [Unstable features](unstable-features.md)
diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md
new file mode 100644 (file)
index 0000000..dd3aa5d
--- /dev/null
@@ -0,0 +1,82 @@
+# How to write documentation
+
+This chapter covers not only how to write documentation but specifically
+how to write **good** documentation.  Something to keep in mind when
+writing documentation is that your audience is not just yourself but others
+who simply don't have the context you do.  It is important to be as clear
+as you can, and as complete as possible.  As a rule of thumb: the more
+documentation you write for your crate the better.  If an item is public
+then it should be documented.
+
+## Basic structure
+
+It is recommended that each item's documentation follows this basic structure:
+
+```text
+[short sentence explaining what it is]
+
+[more detailed explanation]
+
+[at least one code example that users can copy/paste to try it]
+
+[even more advanced explanations if necessary]
+```
+
+This basic structure should be straightforward to follow when writing your
+documentation and, while you might think that a code example is trivial,
+the examples are really important because they can help your users to
+understand what an item is, how it is used, and for what purpose it exists.
+
+Let's see an example coming from the [standard library] by taking a look at the
+[`std::env::args()`][env::args] function:
+
+``````text
+Returns the arguments which this program was started with (normally passed
+via the command line).
+
+The first element is traditionally the path of the executable, but it can be
+set to arbitrary text, and may not even exist. This means this property should
+not be relied upon for security purposes.
+
+On Unix systems shell usually expands unquoted arguments with glob patterns
+(such as `*` and `?`). On Windows this is not done, and such arguments are
+passed as-is.
+
+# Panics
+
+The returned iterator will panic during iteration if any argument to the
+process is not valid unicode. If this is not desired,
+use the [`args_os`] function instead.
+
+# Examples
+
+```
+use std::env;
+
+// Prints each argument on a separate line
+for argument in env::args() {
+    println!("{}", argument);
+}
+```
+
+[`args_os`]: ./fn.args_os.html
+``````
+
+As you can see, it follows the structure detailed above: it starts with a short
+sentence explaining what the functions does, then it provides more information
+and finally provides a code example.
+
+## Markdown
+
+`rustdoc` is using the [commonmark markdown specification]. You might be
+interested into taking a look at their website to see what's possible to do.
+
+## Lints
+
+To be sure that you didn't miss any item without documentation or code examples,
+you can take a look at the rustdoc lints [here][rustdoc-lints].
+
+[standard library]: https://doc.rust-lang.org/stable/std/index.html
+[env::args]: https://doc.rust-lang.org/stable/std/env/fn.args.html
+[commonmark markdown specification]: https://commonmark.org/
+[rustdoc-lints]: lints.md
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
new file mode 100644 (file)
index 0000000..beb2556
--- /dev/null
@@ -0,0 +1,119 @@
+# Lints
+
+`rustdoc` provides lints to help you writing and testing your documentation. You
+can use them like any other lints by doing this:
+
+```rust,ignore
+#![allow(missing_docs)] // allowing the lint, no message
+#![warn(missing_docs)] // warn if there is missing docs
+#![deny(missing_docs)] // rustdoc will fail if there is missing docs
+```
+
+Here is the list of the lints provided by `rustdoc`:
+
+## intra_doc_link_resolution_failure
+
+This lint **warns by default** and is **nightly-only**. This lint detects when
+an intra-doc link fails to get resolved. For example:
+
+```rust
+/// I want to link to [`Inexistent`] but it doesn't exist!
+pub fn foo() {}
+```
+
+You'll get a warning saying:
+
+```text
+error: `[`Inexistent`]` cannot be resolved, ignoring it...
+```
+
+## missing_docs
+
+This lint is **allowed by default**. It detects items missing documentation.
+For example:
+
+```rust
+#![warn(missing_docs)]
+
+pub fn undocumented() {}
+# fn main() {}
+```
+
+The `undocumented` function will then have the following warning:
+
+```text
+warning: missing documentation for a function
+  --> your-crate/lib.rs:3:1
+   |
+ 3 | pub fn undocumented() {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+```
+
+## missing_doc_code_examples
+
+This lint is **allowed by default**. It detects when a documentation block
+is missing a code example. For example:
+
+```rust
+#![warn(missing_doc_code_examples)]
+
+/// There is no code example!
+pub fn no_code_example() {}
+# fn main() {}
+```
+
+The `no_code_example` function will then have the following warning:
+
+```text
+warning: Missing code example in this documentation
+  --> your-crate/lib.rs:3:1
+   |
+LL | /// There is no code example!
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+```
+
+To fix the lint, you need to add a code example into the documentation block:
+
+```rust
+/// There is no code example!
+///
+/// ```
+/// println!("calling no_code_example...");
+/// no_code_example();
+/// println!("we called no_code_example!");
+/// ```
+pub fn no_code_example() {}
+```
+
+## private_doc_tests
+
+This lint is **allowed by default**. It detects documentation tests when they
+are on a private item. For example:
+
+```rust
+#![warn(private_doc_tests)]
+
+mod foo {
+    /// private doc test
+    ///
+    /// ```
+    /// assert!(false);
+    /// ```
+    fn bar() {}
+}
+# fn main() {}
+```
+
+Which will give:
+
+```text
+warning: Documentation test in private item
+  --> your-crate/lib.rs:4:1
+   |
+ 4 | /     /// private doc test
+ 5 | |     ///
+ 6 | |     /// ```
+ 7 | |     /// assert!(false);
+ 8 | |     /// ```
+   | |___________^
+```
index 4b9e82c7cfee9abd16cc4f0a99d8c1ad2187ec28..b5d61a3fd4e786ca6b9beea4791407aa56bef29f 100644 (file)
@@ -235,7 +235,6 @@ macro_rules! usize_isize_from_xe_bytes_doc {
 "}
 }
 
-// `Int` + `SignedInt` implemented for signed integers
 macro_rules! int_impl {
     ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr,
      $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
@@ -2303,7 +2302,6 @@ impl isize {
          usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
 }
 
-// `Int` + `UnsignedInt` implemented for unsigned integers
 macro_rules! uint_impl {
     ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr,
         $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
index 93d0627ac6e401415c58d8a8e539c990121ea7dd..fabb0a59da81dadf3f8731a1ce57d0995a7adc04 100644 (file)
@@ -22,8 +22,9 @@
 use crate::ty::{self, TyCtxt};
 use crate::util::nodemap::{FxHashSet, FxHashMap};
 
-use std::mem::replace;
 use std::cmp::Ordering;
+use std::mem::replace;
+use std::num::NonZeroU32;
 
 #[derive(PartialEq, Clone, Copy, Debug)]
 pub enum StabilityLevel {
@@ -441,7 +442,7 @@ pub fn new(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
                 let stability = tcx.intern_stability(Stability {
                     level: attr::StabilityLevel::Unstable {
                         reason: Some(Symbol::intern(reason)),
-                        issue: 27812,
+                        issue: NonZeroU32::new(27812),
                         is_soft: false,
                     },
                     feature: sym::rustc_private,
@@ -488,7 +489,7 @@ pub fn report_unstable(
     sess: &Session,
     feature: Symbol,
     reason: Option<Symbol>,
-    issue: u32,
+    issue: Option<NonZeroU32>,
     is_soft: bool,
     span: Span,
     soft_handler: impl FnOnce(&'static lint::Lint, Span, &str),
@@ -520,7 +521,7 @@ pub fn report_unstable(
             soft_handler(lint::builtin::SOFT_UNSTABLE, span, &msg)
         } else {
             emit_feature_err(
-                &sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg
+                &sess.parse_sess, feature, span, GateIssue::Library(issue), &msg
             );
         }
     }
@@ -637,7 +638,7 @@ pub enum EvalResult {
     Deny {
         feature: Symbol,
         reason: Option<Symbol>,
-        issue: u32,
+        issue: Option<NonZeroU32>,
         is_soft: bool,
     },
     /// The item does not have the `#[stable]` or `#[unstable]` marker assigned.
@@ -758,7 +759,7 @@ pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> Eva
                 // the `-Z force-unstable-if-unmarked` flag present (we're
                 // compiling a compiler crate), then let this missing feature
                 // annotation slide.
-                if feature == sym::rustc_private && issue == 27812 {
+                if feature == sym::rustc_private && issue == NonZeroU32::new(27812) {
                     if self.sess.opts.debugging_opts.force_unstable_if_unmarked {
                         return EvalResult::Allow;
                     }
index 0f535249b5e2afa3ebacbe2fa95017f5f9366c2e..5baf0c5948f28a5481a25ee1111f52494d9c7349 100644 (file)
@@ -1,6 +1,7 @@
 use rustc_target::abi::{Align, Size};
 use rustc_data_structures::fx::{FxHashSet};
 use std::cmp::{self, Ordering};
+use rustc_data_structures::sync::Lock;
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub struct VariantInfo {
@@ -44,13 +45,13 @@ pub struct TypeSizeInfo {
     pub variants: Vec<VariantInfo>,
 }
 
-#[derive(PartialEq, Eq, Debug, Default)]
+#[derive(Default)]
 pub struct CodeStats {
-    type_sizes: FxHashSet<TypeSizeInfo>,
+    type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
 }
 
 impl CodeStats {
-    pub fn record_type_size<S: ToString>(&mut self,
+    pub fn record_type_size<S: ToString>(&self,
                                          kind: DataTypeKind,
                                          type_desc: S,
                                          align: Align,
@@ -73,11 +74,12 @@ pub fn record_type_size<S: ToString>(&mut self,
             opt_discr_size: opt_discr_size.map(|s| s.bytes()),
             variants,
         };
-        self.type_sizes.insert(info);
+        self.type_sizes.borrow_mut().insert(info);
     }
 
     pub fn print_type_sizes(&self) {
-        let mut sorted: Vec<_> = self.type_sizes.iter().collect();
+        let type_sizes = self.type_sizes.borrow();
+        let mut sorted: Vec<_> = type_sizes.iter().collect();
 
         // Primary sort: large-to-small.
         // Secondary sort: description (dictionary order)
index 92e8e92d02a74e4cb737b5ba96c1998343307c2e..9792223ea15063b2893b553bb84c293635a118f4 100644 (file)
@@ -41,6 +41,7 @@
 use std::env;
 use std::fmt;
 use std::io::Write;
+use std::num::NonZeroU32;
 use std::path::PathBuf;
 use std::time::Duration;
 use std::sync::Arc;
@@ -124,7 +125,7 @@ pub struct Session {
     pub perf_stats: PerfStats,
 
     /// Data about code being compiled, gathered during compilation.
-    pub code_stats: Lock<CodeStats>,
+    pub code_stats: CodeStats,
 
     /// If `-zfuel=crate=n` is specified, `Some(crate)`.
     optimization_fuel_crate: Option<String>,
@@ -183,7 +184,7 @@ enum DiagnosticBuilderMethod {
 pub enum DiagnosticMessageId {
     ErrorId(u16), // EXXXX error code as integer
     LintId(lint::LintId),
-    StabilityId(u32), // issue number
+    StabilityId(Option<NonZeroU32>), // issue number
 }
 
 impl From<&'static lint::Lint> for DiagnosticMessageId {
index e5f22277f8e31bb25cbc5c8664ee30c04afdf95c..972452601ddd5c6ef192bf19a277177f8d76ce34 100644 (file)
@@ -1614,13 +1614,13 @@ fn record_layout_for_printing_outlined(&self, layout: TyLayout<'tcx>) {
         // (delay format until we actually need it)
         let record = |kind, packed, opt_discr_size, variants| {
             let type_desc = format!("{:?}", layout.ty);
-            self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
-                                                                   type_desc,
-                                                                   layout.align.abi,
-                                                                   layout.size,
-                                                                   packed,
-                                                                   opt_discr_size,
-                                                                   variants);
+            self.tcx.sess.code_stats.record_type_size(kind,
+                                                      type_desc,
+                                                      layout.align.abi,
+                                                      layout.size,
+                                                      packed,
+                                                      opt_discr_size,
+                                                      variants);
         };
 
         let adt_def = match layout.ty.kind {
index f2da4ae71f56aa63f80dd536ae9df143c08d1d48..10bc6599e7592ac64f8d22447bdc643c2ad45cd8 100644 (file)
@@ -393,7 +393,7 @@ pub fn run_compiler(
         mem::drop(compiler.global_ctxt()?.take());
 
         if sess.opts.debugging_opts.print_type_sizes {
-            sess.code_stats.borrow().print_type_sizes();
+            sess.code_stats.print_type_sizes();
         }
 
         compiler.link()?;
index fb5cccf61a7a9877719138bdacedd12d061e834c..8ee28875c625931bd277ad2cb8814aa854cc686d 100644 (file)
@@ -15,8 +15,6 @@
 
 use emitter::{Emitter, EmitterWriter, is_case_difference};
 use registry::Registry;
-#[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::{self, Lrc, Lock};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::stable_hasher::StableHasher;
@@ -54,7 +52,7 @@
 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
 // (See also the comment on `DiagnosticBuilderInner`.)
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PResult<'_, bool>, 16);
+rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
 
 /// Indicates the confidence in the correctness of a suggestion.
 ///
index 8989d2e15de997a3df7910c41402332f211e1795..982330baf9c9568cc386b2b5adce11befa4c3dbd 100644 (file)
@@ -586,8 +586,10 @@ enum Constructor<'tcx> {
     ConstantValue(&'tcx ty::Const<'tcx>, Span),
     /// Ranges of literal values (`2..=5` and `2..5`).
     ConstantRange(u128, u128, Ty<'tcx>, RangeEnd, Span),
-    /// Array patterns of length n.
-    Slice(u64),
+    /// Array patterns of length `n`.
+    FixedLenSlice(u64),
+    /// Slice patterns. Captures any array constructor of `length >= i + j`.
+    VarLenSlice(u64, u64),
 }
 
 // Ignore spans when comparing, they don't carry semantic information as they are only for lints.
@@ -601,7 +603,11 @@ fn eq(&self, other: &Self) -> bool {
                 Constructor::ConstantRange(a_start, a_end, a_ty, a_range_end, _),
                 Constructor::ConstantRange(b_start, b_end, b_ty, b_range_end, _),
             ) => a_start == b_start && a_end == b_end && a_ty == b_ty && a_range_end == b_range_end,
-            (Constructor::Slice(a), Constructor::Slice(b)) => a == b,
+            (Constructor::FixedLenSlice(a), Constructor::FixedLenSlice(b)) => a == b,
+            (
+                Constructor::VarLenSlice(a_prefix, a_suffix),
+                Constructor::VarLenSlice(b_prefix, b_suffix),
+            ) => a_prefix == b_prefix && a_suffix == b_suffix,
             _ => false,
         }
     }
@@ -610,7 +616,7 @@ fn eq(&self, other: &Self) -> bool {
 impl<'tcx> Constructor<'tcx> {
     fn is_slice(&self) -> bool {
         match self {
-            Slice { .. } => true,
+            FixedLenSlice { .. } | VarLenSlice { .. } => true,
             _ => false,
         }
     }
@@ -644,7 +650,8 @@ fn display(&self, tcx: TyCtxt<'tcx>) -> String {
                     ty::Const::from_bits(tcx, *hi, ty),
                 )
             }
-            Constructor::Slice(val) => format!("[{}]", val),
+            Constructor::FixedLenSlice(val) => format!("[{}]", val),
+            Constructor::VarLenSlice(prefix, suffix) => format!("[{}, .., {}]", prefix, suffix),
             _ => bug!("bad constructor being displayed: `{:?}", self),
         }
     }
@@ -657,31 +664,114 @@ fn subtract_ctors(
         param_env: ty::ParamEnv<'tcx>,
         other_ctors: &Vec<Constructor<'tcx>>,
     ) -> Vec<Constructor<'tcx>> {
-        let mut refined_ctors = vec![self.clone()];
-        for other_ctor in other_ctors {
-            if other_ctor == self {
-                // If a constructor appears in a `match` arm, we can
-                // eliminate it straight away.
-                refined_ctors = vec![]
-            } else if let Some(interval) = IntRange::from_ctor(tcx, param_env, other_ctor) {
-                // Refine the required constructors for the type by subtracting
-                // the range defined by the current constructor pattern.
-                refined_ctors = interval.subtract_from(tcx, param_env, refined_ctors);
+        match *self {
+            // Those constructors can only match themselves.
+            Single | Variant(_) => {
+                if other_ctors.iter().any(|c| c == self) {
+                    vec![]
+                } else {
+                    vec![self.clone()]
+                }
+            }
+            FixedLenSlice(self_len) => {
+                let overlaps = |c: &Constructor<'_>| match *c {
+                    FixedLenSlice(other_len) => other_len == self_len,
+                    VarLenSlice(prefix, suffix) => prefix + suffix <= self_len,
+                    _ => false,
+                };
+                if other_ctors.iter().any(overlaps) { vec![] } else { vec![self.clone()] }
             }
+            VarLenSlice(..) => {
+                let mut remaining_ctors = vec![self.clone()];
+
+                // For each used ctor, subtract from the current set of constructors.
+                // Naming: we remove the "neg" constructors from the "pos" ones.
+                // Remember, `VarLenSlice(i, j)` covers the union of `FixedLenSlice` from
+                // `i + j` to infinity.
+                for neg_ctor in other_ctors {
+                    remaining_ctors = remaining_ctors
+                        .into_iter()
+                        .flat_map(|pos_ctor| -> SmallVec<[Constructor<'tcx>; 1]> {
+                            // Compute `pos_ctor \ neg_ctor`.
+                            match (&pos_ctor, neg_ctor) {
+                                (&FixedLenSlice(pos_len), &VarLenSlice(neg_prefix, neg_suffix)) => {
+                                    let neg_len = neg_prefix + neg_suffix;
+                                    if neg_len <= pos_len {
+                                        smallvec![]
+                                    } else {
+                                        smallvec![pos_ctor]
+                                    }
+                                }
+                                (
+                                    &VarLenSlice(pos_prefix, pos_suffix),
+                                    &VarLenSlice(neg_prefix, neg_suffix),
+                                ) => {
+                                    let neg_len = neg_prefix + neg_suffix;
+                                    let pos_len = pos_prefix + pos_suffix;
+                                    if neg_len <= pos_len {
+                                        smallvec![]
+                                    } else {
+                                        (pos_len..neg_len).map(FixedLenSlice).collect()
+                                    }
+                                }
+                                (&VarLenSlice(pos_prefix, pos_suffix), &FixedLenSlice(neg_len)) => {
+                                    let pos_len = pos_prefix + pos_suffix;
+                                    if neg_len < pos_len {
+                                        smallvec![pos_ctor]
+                                    } else {
+                                        (pos_len..neg_len)
+                                            .map(FixedLenSlice)
+                                            // We know that `neg_len + 1 >= pos_len >= pos_suffix`.
+                                            .chain(Some(VarLenSlice(
+                                                neg_len + 1 - pos_suffix,
+                                                pos_suffix,
+                                            )))
+                                            .collect()
+                                    }
+                                }
+                                _ if pos_ctor == *neg_ctor => smallvec![],
+                                _ => smallvec![pos_ctor],
+                            }
+                        })
+                        .collect();
+
+                    // If the constructors that have been considered so far already cover
+                    // the entire range of `self`, no need to look at more constructors.
+                    if remaining_ctors.is_empty() {
+                        break;
+                    }
+                }
 
-            // If the constructor patterns that have been considered so far
-            // already cover the entire range of values, then we know the
-            // constructor is not missing, and we can move on to the next one.
-            if refined_ctors.is_empty() {
-                break;
+                remaining_ctors
             }
-        }
+            ConstantRange(..) | ConstantValue(..) => {
+                let mut remaining_ctors = vec![self.clone()];
+                for other_ctor in other_ctors {
+                    if other_ctor == self {
+                        // If a constructor appears in a `match` arm, we can
+                        // eliminate it straight away.
+                        remaining_ctors = vec![]
+                    } else if let Some(interval) = IntRange::from_ctor(tcx, param_env, other_ctor) {
+                        // Refine the required constructors for the type by subtracting
+                        // the range defined by the current constructor pattern.
+                        remaining_ctors = interval.subtract_from(tcx, param_env, remaining_ctors);
+                    }
 
-        // If a constructor has not been matched, then it is missing.
-        // We add `refined_ctors` instead of `self`, because then we can
-        // provide more detailed error information about precisely which
-        // ranges have been omitted.
-        refined_ctors
+                    // If the constructor patterns that have been considered so far
+                    // already cover the entire range of values, then we know the
+                    // constructor is not missing, and we can move on to the next one.
+                    if remaining_ctors.is_empty() {
+                        break;
+                    }
+                }
+
+                // If a constructor has not been matched, then it is missing.
+                // We add `remaining_ctors` instead of `self`, because then we can
+                // provide more detailed error information about precisely which
+                // ranges have been omitted.
+                remaining_ctors
+            }
+        }
     }
 
     /// This returns one wildcard pattern for each argument to this constructor.
@@ -689,12 +779,68 @@ fn wildcard_subpatterns<'a>(
         &self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
         ty: Ty<'tcx>,
-    ) -> impl Iterator<Item = Pat<'tcx>> + DoubleEndedIterator {
-        constructor_sub_pattern_tys(cx, self, ty).into_iter().map(|ty| Pat {
-            ty,
-            span: DUMMY_SP,
-            kind: box PatKind::Wild,
-        })
+    ) -> Vec<Pat<'tcx>> {
+        debug!("wildcard_subpatterns({:#?}, {:?})", self, ty);
+        match ty.kind {
+            ty::Tuple(ref fs) => {
+                fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect()
+            }
+            ty::Slice(ty) | ty::Array(ty, _) => match *self {
+                FixedLenSlice(length) => (0..length).map(|_| Pat::wildcard_from_ty(ty)).collect(),
+                VarLenSlice(prefix, suffix) => {
+                    (0..prefix + suffix).map(|_| Pat::wildcard_from_ty(ty)).collect()
+                }
+                ConstantValue(..) => vec![],
+                _ => bug!("bad slice pattern {:?} {:?}", self, ty),
+            },
+            ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)],
+            ty::Adt(adt, substs) => {
+                if adt.is_box() {
+                    // Use T as the sub pattern type of Box<T>.
+                    vec![Pat::wildcard_from_ty(substs.type_at(0))]
+                } else {
+                    let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
+                    let is_non_exhaustive =
+                        variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
+                    variant
+                        .fields
+                        .iter()
+                        .map(|field| {
+                            let is_visible =
+                                adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
+                            let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs));
+                            match (is_visible, is_non_exhaustive, is_uninhabited) {
+                                // Treat all uninhabited types in non-exhaustive variants as
+                                // `TyErr`.
+                                (_, true, true) => cx.tcx.types.err,
+                                // Treat all non-visible fields as `TyErr`. They can't appear in
+                                // any other pattern from this match (because they are private), so
+                                // their type does not matter - but we don't want to know they are
+                                // uninhabited.
+                                (false, ..) => cx.tcx.types.err,
+                                (true, ..) => {
+                                    let ty = field.ty(cx.tcx, substs);
+                                    match ty.kind {
+                                        // If the field type returned is an array of an unknown
+                                        // size return an TyErr.
+                                        ty::Array(_, len)
+                                            if len
+                                                .try_eval_usize(cx.tcx, cx.param_env)
+                                                .is_none() =>
+                                        {
+                                            cx.tcx.types.err
+                                        }
+                                        _ => ty,
+                                    }
+                                }
+                            }
+                        })
+                        .map(Pat::wildcard_from_ty)
+                        .collect()
+                }
+            }
+            _ => vec![],
+        }
     }
 
     /// This computes the arity of a constructor. The arity of a constructor
@@ -707,7 +853,8 @@ fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 {
         match ty.kind {
             ty::Tuple(ref fs) => fs.len() as u64,
             ty::Slice(..) | ty::Array(..) => match *self {
-                Slice(length) => length,
+                FixedLenSlice(length) => length,
+                VarLenSlice(prefix, suffix) => prefix + suffix,
                 ConstantValue(..) => 0,
                 _ => bug!("bad slice pattern {:?} {:?}", self, ty),
             },
@@ -764,9 +911,18 @@ fn apply<'a>(
 
             ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() },
 
-            ty::Slice(_) | ty::Array(..) => {
-                PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
-            }
+            ty::Slice(_) | ty::Array(..) => match self {
+                FixedLenSlice(_) => {
+                    PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
+                }
+                VarLenSlice(prefix_len, _suffix_len) => {
+                    let prefix = subpatterns.by_ref().take(*prefix_len as usize).collect();
+                    let suffix = subpatterns.collect();
+                    let wild = Pat::wildcard_from_ty(ty);
+                    PatKind::Slice { prefix, slice: Some(wild), suffix }
+                }
+                _ => bug!("bad slice pattern {:?} {:?}", self, ty),
+            },
 
             _ => match *self {
                 ConstantValue(value, _) => PatKind::Constant { value },
@@ -784,7 +940,7 @@ fn apply<'a>(
 
     /// Like `apply`, but where all the subpatterns are wildcards `_`.
     fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
-        let subpatterns = self.wildcard_subpatterns(cx, ty).rev();
+        let subpatterns = self.wildcard_subpatterns(cx, ty).into_iter().rev();
         self.apply(cx, ty, subpatterns)
     }
 }
@@ -831,7 +987,7 @@ fn apply_constructor(
     fn apply_wildcard(self, ty: Ty<'tcx>) -> Self {
         match self {
             UsefulWithWitness(witnesses) => {
-                let wild = Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
+                let wild = Pat::wildcard_from_ty(ty);
                 UsefulWithWitness(
                     witnesses
                         .into_iter()
@@ -884,7 +1040,6 @@ pub enum WitnessPreference {
 #[derive(Copy, Clone, Debug)]
 struct PatCtxt<'tcx> {
     ty: Ty<'tcx>,
-    max_slice_length: u64,
     span: Span,
 }
 
@@ -980,14 +1135,14 @@ fn all_constructors<'a, 'tcx>(
             .collect(),
         ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
             let len = len.eval_usize(cx.tcx, cx.param_env);
-            if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { vec![Slice(len)] }
+            if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { vec![FixedLenSlice(len)] }
         }
         // Treat arrays of a constant but unknown length like slices.
         ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => {
             if cx.is_uninhabited(sub_ty) {
-                vec![Slice(0)]
+                vec![FixedLenSlice(0)]
             } else {
-                (0..pcx.max_slice_length + 1).map(|length| Slice(length)).collect()
+                vec![VarLenSlice(0, 0)]
             }
         }
         ty::Adt(def, substs) if def.is_enum() => def
@@ -1042,108 +1197,6 @@ fn all_constructors<'a, 'tcx>(
     ctors
 }
 
-fn max_slice_length<'p, 'a, 'tcx, I>(cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64
-where
-    I: Iterator<Item = &'p Pat<'tcx>>,
-    'tcx: 'p,
-{
-    // The exhaustiveness-checking paper does not include any details on
-    // checking variable-length slice patterns. However, they are matched
-    // by an infinite collection of fixed-length array patterns.
-    //
-    // Checking the infinite set directly would take an infinite amount
-    // of time. However, it turns out that for each finite set of
-    // patterns `P`, all sufficiently large array lengths are equivalent:
-    //
-    // Each slice `s` with a "sufficiently-large" length `l â‰¥ L` that applies
-    // to exactly the subset `Pâ‚œ` of `P` can be transformed to a slice
-    // `sₘ` for each sufficiently-large length `m` that applies to exactly
-    // the same subset of `P`.
-    //
-    // Because of that, each witness for reachability-checking from one
-    // of the sufficiently-large lengths can be transformed to an
-    // equally-valid witness from any other length, so we only have
-    // to check slice lengths from the "minimal sufficiently-large length"
-    // and below.
-    //
-    // Note that the fact that there is a *single* `sₘ` for each `m`
-    // not depending on the specific pattern in `P` is important: if
-    // you look at the pair of patterns
-    //     `[true, ..]`
-    //     `[.., false]`
-    // Then any slice of length â‰¥1 that matches one of these two
-    // patterns can be trivially turned to a slice of any
-    // other length â‰¥1 that matches them and vice-versa - for
-    // but the slice from length 2 `[false, true]` that matches neither
-    // of these patterns can't be turned to a slice from length 1 that
-    // matches neither of these patterns, so we have to consider
-    // slices from length 2 there.
-    //
-    // Now, to see that that length exists and find it, observe that slice
-    // patterns are either "fixed-length" patterns (`[_, _, _]`) or
-    // "variable-length" patterns (`[_, .., _]`).
-    //
-    // For fixed-length patterns, all slices with lengths *longer* than
-    // the pattern's length have the same outcome (of not matching), so
-    // as long as `L` is greater than the pattern's length we can pick
-    // any `sₘ` from that length and get the same result.
-    //
-    // For variable-length patterns, the situation is more complicated,
-    // because as seen above the precise value of `sₘ` matters.
-    //
-    // However, for each variable-length pattern `p` with a prefix of length
-    // `plâ‚š` and suffix of length `slâ‚š`, only the first `plâ‚š` and the last
-    // `slâ‚š` elements are examined.
-    //
-    // Therefore, as long as `L` is positive (to avoid concerns about empty
-    // types), all elements after the maximum prefix length and before
-    // the maximum suffix length are not examined by any variable-length
-    // pattern, and therefore can be added/removed without affecting
-    // them - creating equivalent patterns from any sufficiently-large
-    // length.
-    //
-    // Of course, if fixed-length patterns exist, we must be sure
-    // that our length is large enough to miss them all, so
-    // we can pick `L = max(FIXED_LEN+1 âˆª {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
-    //
-    // for example, with the above pair of patterns, all elements
-    // but the first and last can be added/removed, so any
-    // witness of length â‰¥2 (say, `[false, false, true]`) can be
-    // turned to a witness from any other length â‰¥2.
-
-    let mut max_prefix_len = 0;
-    let mut max_suffix_len = 0;
-    let mut max_fixed_len = 0;
-
-    for row in patterns {
-        match *row.kind {
-            PatKind::Constant { value } => {
-                // extract the length of an array/slice from a constant
-                match (value.val, &value.ty.kind) {
-                    (_, ty::Array(_, n)) => {
-                        max_fixed_len = cmp::max(max_fixed_len, n.eval_usize(cx.tcx, cx.param_env))
-                    }
-                    (ConstValue::Slice { start, end, .. }, ty::Slice(_)) => {
-                        max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64)
-                    }
-                    _ => {}
-                }
-            }
-            PatKind::Slice { ref prefix, slice: None, ref suffix } => {
-                let fixed_len = prefix.len() as u64 + suffix.len() as u64;
-                max_fixed_len = cmp::max(max_fixed_len, fixed_len);
-            }
-            PatKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
-                max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
-                max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
-            }
-            _ => {}
-        }
-    }
-
-    cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len)
-}
-
 /// An inclusive interval, used for precise integer exhaustiveness checking.
 /// `IntRange`s always store a contiguous range. This means that values are
 /// encoded such that `0` encodes the minimum value for the integer,
@@ -1508,20 +1561,19 @@ pub fn is_useful<'p, 'a, 'tcx>(
         // introducing uninhabited patterns for inaccessible fields. We
         // need to figure out how to model that.
         ty,
-        max_slice_length: max_slice_length(cx, matrix.heads().chain(Some(v.head()))),
         span,
     };
 
     debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
 
-    if let Some(constructors) = pat_constructors(cx, v.head(), pcx) {
-        debug!("is_useful - expanding constructors: {:#?}", constructors);
+    if let Some(constructor) = pat_constructor(cx, v.head(), pcx) {
+        debug!("is_useful - expanding constructor: {:#?}", constructor);
         split_grouped_constructors(
             cx.tcx,
             cx.param_env,
-            constructors,
+            pcx,
+            vec![constructor],
             matrix,
-            pcx.ty,
             pcx.span,
             Some(hir_id),
         )
@@ -1533,7 +1585,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
         debug!("is_useful - expanding wildcard");
 
         let used_ctors: Vec<Constructor<'_>> =
-            matrix.heads().flat_map(|p| pat_constructors(cx, p, pcx).unwrap_or(vec![])).collect();
+            matrix.heads().filter_map(|p| pat_constructor(cx, p, pcx)).collect();
         debug!("used_ctors = {:#?}", used_ctors);
         // `all_ctors` are all the constructors for the given type, which
         // should all be represented (or caught with the wild pattern `_`).
@@ -1583,19 +1635,13 @@ pub fn is_useful<'p, 'a, 'tcx>(
 
         if missing_ctors.is_empty() && !is_non_exhaustive {
             let (all_ctors, _) = missing_ctors.into_inner();
-            split_grouped_constructors(
-                cx.tcx,
-                cx.param_env,
-                all_ctors,
-                matrix,
-                pcx.ty,
-                DUMMY_SP,
-                None,
-            )
-            .into_iter()
-            .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
-            .find(|result| result.is_useful())
-            .unwrap_or(NotUseful)
+            split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None)
+                .into_iter()
+                .map(|c| {
+                    is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id)
+                })
+                .find(|result| result.is_useful())
+                .unwrap_or(NotUseful)
         } else {
             let matrix = matrix.specialize_wildcard();
             let v = v.to_tail();
@@ -1673,7 +1719,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
 ) -> Usefulness<'tcx> {
     debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
 
-    let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty).collect();
+    let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty);
     let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
     let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
     v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
@@ -1682,44 +1728,39 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
         .unwrap_or(NotUseful)
 }
 
-/// Determines the constructors that the given pattern can be specialized to.
-///
-/// In most cases, there's only one constructor that a specific pattern
-/// represents, such as a specific enum variant or a specific literal value.
-/// Slice patterns, however, can match slices of different lengths. For instance,
-/// `[a, b, tail @ ..]` can match a slice of length 2, 3, 4 and so on.
-///
+/// Determines the constructor that the given pattern can be specialized to.
 /// Returns `None` in case of a catch-all, which can't be specialized.
-fn pat_constructors<'tcx>(
+fn pat_constructor<'tcx>(
     cx: &mut MatchCheckCtxt<'_, 'tcx>,
     pat: &Pat<'tcx>,
     pcx: PatCtxt<'tcx>,
-) -> Option<Vec<Constructor<'tcx>>> {
+) -> Option<Constructor<'tcx>> {
     match *pat.kind {
-        PatKind::AscribeUserType { ref subpattern, .. } => pat_constructors(cx, subpattern, pcx),
+        PatKind::AscribeUserType { ref subpattern, .. } => pat_constructor(cx, subpattern, pcx),
         PatKind::Binding { .. } | PatKind::Wild => None,
-        PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(vec![Single]),
+        PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(Single),
         PatKind::Variant { adt_def, variant_index, .. } => {
-            Some(vec![Variant(adt_def.variants[variant_index].def_id)])
+            Some(Variant(adt_def.variants[variant_index].def_id))
         }
-        PatKind::Constant { value } => Some(vec![ConstantValue(value, pat.span)]),
-        PatKind::Range(PatRange { lo, hi, end }) => Some(vec![ConstantRange(
+        PatKind::Constant { value } => Some(ConstantValue(value, pat.span)),
+        PatKind::Range(PatRange { lo, hi, end }) => Some(ConstantRange(
             lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
             hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
             lo.ty,
             end,
             pat.span,
-        )]),
+        )),
         PatKind::Array { .. } => match pcx.ty.kind {
-            ty::Array(_, length) => Some(vec![Slice(length.eval_usize(cx.tcx, cx.param_env))]),
+            ty::Array(_, length) => Some(FixedLenSlice(length.eval_usize(cx.tcx, cx.param_env))),
             _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty),
         },
         PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-            let pat_len = prefix.len() as u64 + suffix.len() as u64;
+            let prefix = prefix.len() as u64;
+            let suffix = suffix.len() as u64;
             if slice.is_some() {
-                Some((pat_len..pcx.max_slice_length + 1).map(Slice).collect())
+                Some(VarLenSlice(prefix, suffix))
             } else {
-                Some(vec![Slice(pat_len)])
+                Some(FixedLenSlice(prefix + suffix))
             }
         }
         PatKind::Or { .. } => {
@@ -1728,68 +1769,6 @@ fn pat_constructors<'tcx>(
     }
 }
 
-/// This computes the types of the sub patterns that a constructor should be
-/// expanded to.
-///
-/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
-fn constructor_sub_pattern_tys<'a, 'tcx>(
-    cx: &MatchCheckCtxt<'a, 'tcx>,
-    ctor: &Constructor<'tcx>,
-    ty: Ty<'tcx>,
-) -> Vec<Ty<'tcx>> {
-    debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
-    match ty.kind {
-        ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(),
-        ty::Slice(ty) | ty::Array(ty, _) => match *ctor {
-            Slice(length) => (0..length).map(|_| ty).collect(),
-            ConstantValue(..) => vec![],
-            _ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
-        },
-        ty::Ref(_, rty, _) => vec![rty],
-        ty::Adt(adt, substs) => {
-            if adt.is_box() {
-                // Use T as the sub pattern type of Box<T>.
-                vec![substs.type_at(0)]
-            } else {
-                let variant = &adt.variants[ctor.variant_index_for_adt(cx, adt)];
-                let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
-                variant
-                    .fields
-                    .iter()
-                    .map(|field| {
-                        let is_visible =
-                            adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
-                        let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs));
-                        match (is_visible, is_non_exhaustive, is_uninhabited) {
-                            // Treat all uninhabited types in non-exhaustive variants as `TyErr`.
-                            (_, true, true) => cx.tcx.types.err,
-                            // Treat all non-visible fields as `TyErr`. They can't appear in any
-                            // other pattern from this match (because they are private), so their
-                            // type does not matter - but we don't want to know they are
-                            // uninhabited.
-                            (false, ..) => cx.tcx.types.err,
-                            (true, ..) => {
-                                let ty = field.ty(cx.tcx, substs);
-                                match ty.kind {
-                                    // If the field type returned is an array of an unknown size
-                                    // return an TyErr.
-                                    ty::Array(_, len)
-                                        if len.try_eval_usize(cx.tcx, cx.param_env).is_none() =>
-                                    {
-                                        cx.tcx.types.err
-                                    }
-                                    _ => ty,
-                                }
-                            }
-                        }
-                    })
-                    .collect()
-            }
-        }
-        _ => vec![],
-    }
-}
-
 // checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
 // meaning all other types will compare unequal and thus equal patterns often do not cause the
 // second pattern to lint about unreachable match arms.
@@ -1900,21 +1879,22 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>)
 ///
 /// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
 /// ranges that case.
+///
+/// This also splits variable-length slices into fixed-length slices.
 fn split_grouped_constructors<'p, 'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
+    pcx: PatCtxt<'tcx>,
     ctors: Vec<Constructor<'tcx>>,
     matrix: &Matrix<'p, 'tcx>,
-    ty: Ty<'tcx>,
     span: Span,
     hir_id: Option<HirId>,
 ) -> Vec<Constructor<'tcx>> {
+    let ty = pcx.ty;
     let mut split_ctors = Vec::with_capacity(ctors.len());
 
     for ctor in ctors.into_iter() {
         match ctor {
-            // For now, only ranges may denote groups of "subconstructors", so we only need to
-            // special-case constant ranges.
             ConstantRange(..) if should_treat_range_exhaustively(tcx, &ctor) => {
                 // We only care about finding all the subranges within the range of the constructor
                 // range. Anything else is irrelevant, because it is guaranteed to result in
@@ -1996,6 +1976,121 @@ fn range_borders(r: IntRange<'_>) -> impl Iterator<Item = Border> {
                     split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span));
                 }
             }
+            VarLenSlice(self_prefix, self_suffix) => {
+                // The exhaustiveness-checking paper does not include any details on
+                // checking variable-length slice patterns. However, they are matched
+                // by an infinite collection of fixed-length array patterns.
+                //
+                // Checking the infinite set directly would take an infinite amount
+                // of time. However, it turns out that for each finite set of
+                // patterns `P`, all sufficiently large array lengths are equivalent:
+                //
+                // Each slice `s` with a "sufficiently-large" length `l â‰¥ L` that applies
+                // to exactly the subset `Pâ‚œ` of `P` can be transformed to a slice
+                // `sₘ` for each sufficiently-large length `m` that applies to exactly
+                // the same subset of `P`.
+                //
+                // Because of that, each witness for reachability-checking from one
+                // of the sufficiently-large lengths can be transformed to an
+                // equally-valid witness from any other length, so we only have
+                // to check slice lengths from the "minimal sufficiently-large length"
+                // and below.
+                //
+                // Note that the fact that there is a *single* `sₘ` for each `m`
+                // not depending on the specific pattern in `P` is important: if
+                // you look at the pair of patterns
+                //     `[true, ..]`
+                //     `[.., false]`
+                // Then any slice of length â‰¥1 that matches one of these two
+                // patterns can be trivially turned to a slice of any
+                // other length â‰¥1 that matches them and vice-versa - for
+                // but the slice from length 2 `[false, true]` that matches neither
+                // of these patterns can't be turned to a slice from length 1 that
+                // matches neither of these patterns, so we have to consider
+                // slices from length 2 there.
+                //
+                // Now, to see that that length exists and find it, observe that slice
+                // patterns are either "fixed-length" patterns (`[_, _, _]`) or
+                // "variable-length" patterns (`[_, .., _]`).
+                //
+                // For fixed-length patterns, all slices with lengths *longer* than
+                // the pattern's length have the same outcome (of not matching), so
+                // as long as `L` is greater than the pattern's length we can pick
+                // any `sₘ` from that length and get the same result.
+                //
+                // For variable-length patterns, the situation is more complicated,
+                // because as seen above the precise value of `sₘ` matters.
+                //
+                // However, for each variable-length pattern `p` with a prefix of length
+                // `plâ‚š` and suffix of length `slâ‚š`, only the first `plâ‚š` and the last
+                // `slâ‚š` elements are examined.
+                //
+                // Therefore, as long as `L` is positive (to avoid concerns about empty
+                // types), all elements after the maximum prefix length and before
+                // the maximum suffix length are not examined by any variable-length
+                // pattern, and therefore can be added/removed without affecting
+                // them - creating equivalent patterns from any sufficiently-large
+                // length.
+                //
+                // Of course, if fixed-length patterns exist, we must be sure
+                // that our length is large enough to miss them all, so
+                // we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
+                //
+                // for example, with the above pair of patterns, all elements
+                // but the first and last can be added/removed, so any
+                // witness of length â‰¥2 (say, `[false, false, true]`) can be
+                // turned to a witness from any other length â‰¥2.
+
+                let mut max_prefix_len = self_prefix;
+                let mut max_suffix_len = self_suffix;
+                let mut max_fixed_len = 0;
+
+                for row in matrix.heads() {
+                    match *row.kind {
+                        PatKind::Constant { value } => {
+                            // extract the length of an array/slice from a constant
+                            match (value.val, &value.ty.kind) {
+                                (_, ty::Array(_, n)) => {
+                                    max_fixed_len =
+                                        cmp::max(max_fixed_len, n.eval_usize(tcx, param_env))
+                                }
+                                (ConstValue::Slice { start, end, .. }, ty::Slice(_)) => {
+                                    max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64)
+                                }
+                                _ => {}
+                            }
+                        }
+                        PatKind::Slice { ref prefix, slice: None, ref suffix } => {
+                            let fixed_len = prefix.len() as u64 + suffix.len() as u64;
+                            max_fixed_len = cmp::max(max_fixed_len, fixed_len);
+                        }
+                        PatKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
+                            max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
+                            max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
+                        }
+                        _ => {}
+                    }
+                }
+
+                // For diagnostics, we keep the prefix and suffix lengths separate, so in the case
+                // where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly,
+                // so that `L = max_prefix_len + max_suffix_len`.
+                if max_fixed_len + 1 >= max_prefix_len + max_suffix_len {
+                    // The subtraction can't overflow thanks to the above check.
+                    // The new `max_prefix_len` is also guaranteed to be larger than its previous
+                    // value.
+                    max_prefix_len = max_fixed_len + 1 - max_suffix_len;
+                }
+
+                // `ctor` originally covered the range `(self_prefix + self_suffix..infinity)`. We
+                // now split it into two: lengths smaller than `max_prefix_len + max_suffix_len`
+                // are treated independently as fixed-lengths slices, and lengths above are
+                // captured by a final VarLenSlice constructor.
+                split_ctors.extend(
+                    (self_prefix + self_suffix..max_prefix_len + max_suffix_len).map(FixedLenSlice),
+                );
+                split_ctors.push(VarLenSlice(max_prefix_len, max_suffix_len));
+            }
             // Any other constructor can be used unchanged.
             _ => split_ctors.push(ctor),
         }
@@ -2238,7 +2333,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
 
         PatKind::Array { ref prefix, ref slice, ref suffix }
         | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
-            Slice(..) => {
+            FixedLenSlice(..) | VarLenSlice(..) => {
                 let pat_len = prefix.len() + suffix.len();
                 if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
                     if slice_count == 0 || slice.is_some() {
index 52af8c13e78bedfc4aa633f100650c3be4fef223..ffb3ae44ae1e95a16238459b74d429b73ead8755 100644 (file)
@@ -18,7 +18,7 @@
 
 use std::slice;
 
-use syntax_pos::{MultiSpan, Span, DUMMY_SP};
+use syntax_pos::{MultiSpan, Span};
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
     let body_id = match tcx.hir().as_local_hir_id(def_id) {
@@ -491,7 +491,7 @@ fn check_not_useful(
     matrix: &Matrix<'_, 'tcx>,
     hir_id: HirId,
 ) -> Result<(), Vec<super::Pat<'tcx>>> {
-    let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
+    let wild_pattern = super::Pat::wildcard_from_ty(ty);
     match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
         NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
         UsefulWithWitness(pats) => Err(if pats.is_empty() {
index 0885c9578294d82030bfd39543582759d324ea0a..f613f6f4b99b90a840fb19fe03cbd44adc0bb8f3 100644 (file)
@@ -26,7 +26,7 @@
 use std::cmp::Ordering;
 use std::fmt;
 use syntax::ast;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 #[derive(Clone, Debug)]
 pub enum PatternError {
@@ -55,6 +55,11 @@ pub struct Pat<'tcx> {
     pub kind: Box<PatKind<'tcx>>,
 }
 
+impl<'tcx> Pat<'tcx> {
+    pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
+        Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
+    }
+}
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub struct PatTyProj<'tcx> {
index 38db9cd356cd86b749db17c2d1d604e0aa3291c6..ce7b338345caf6e4fed10c2c7313e40d42ca9cbd 100644 (file)
@@ -4,33 +4,6 @@
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
     pre_link_args.insert(LinkerFlavor::Gcc, vec![
-            // And here, we see obscure linker flags #45. On windows, it has been
-            // found to be necessary to have this flag to compile liblibc.
-            //
-            // First a bit of background. On Windows, the file format is not ELF,
-            // but COFF (at least according to LLVM). COFF doesn't officially allow
-            // for section names over 8 characters, apparently. Our metadata
-            // section, ".note.rustc", you'll note is over 8 characters.
-            //
-            // On more recent versions of gcc on mingw, apparently the section name
-            // is *not* truncated, but rather stored elsewhere in a separate lookup
-            // table. On older versions of gcc, they apparently always truncated th
-            // section names (at least in some cases). Truncating the section name
-            // actually creates "invalid" objects [1] [2], but only for some
-            // introspection tools, not in terms of whether it can be loaded.
-            //
-            // Long story short, passing this flag forces the linker to *not*
-            // truncate section names (so we can find the metadata section after
-            // it's compiled). The real kicker is that rust compiled just fine on
-            // windows for quite a long time *without* this flag, so I have no idea
-            // why it suddenly started failing for liblibc. Regardless, we
-            // definitely don't want section name truncation, so we're keeping this
-            // flag for windows.
-            //
-            // [1] - https://sourceware.org/bugzilla/show_bug.cgi?id=13130
-            // [2] - https://code.google.com/p/go/issues/detail?id=2139
-            "-Wl,--enable-long-section-names".to_string(),
-
             // Tell GCC to avoid linker plugins, because we are not bundling
             // them with Windows installer, and Rust does its own LTO anyways.
             "-fno-use-linker-plugin".to_string(),
index f21fc2df8b91388ac65a68b6e2382558a79c67df..560abeb705704576f7614fa8cb6b2320c669965e 100644 (file)
@@ -3,9 +3,9 @@
 syntax::register_diagnostics! {
 
 E0023: r##"
-A pattern used to match against an enum variant must provide a sub-pattern for
-each field of the enum variant. This error indicates that a pattern attempted to
-extract an incorrect number of fields from a variant.
+A pattern attempted to extract an incorrect number of fields from a variant.
+
+Erroneous code example:
 
 ```
 enum Fruit {
@@ -14,6 +14,9 @@ enum Fruit {
 }
 ```
 
+A pattern used to match against an enum variant must provide a sub-pattern for
+each field of the enum variant.
+
 Here the `Apple` variant has two fields, and should be matched against like so:
 
 ```
@@ -53,8 +56,9 @@ enum Fruit {
 "##,
 
 E0025: r##"
-Each field of a struct can only be bound once in a pattern. Erroneous code
-example:
+Each field of a struct can only be bound once in a pattern.
+
+Erroneous code example:
 
 ```compile_fail,E0025
 struct Foo {
@@ -89,65 +93,47 @@ fn main(){
 "##,
 
 E0026: r##"
-This error indicates that a struct pattern attempted to extract a non-existent
-field from a struct. Struct fields are identified by the name used before the
-colon `:` so struct patterns should resemble the declaration of the struct type
-being matched.
-
-```
-// Correct matching.
-struct Thing {
-    x: u32,
-    y: u32
-}
-
-let thing = Thing { x: 1, y: 2 };
+A struct pattern attempted to extract a non-existent field from a struct.
 
-match thing {
-    Thing { x: xfield, y: yfield } => {}
-}
-```
-
-If you are using shorthand field patterns but want to refer to the struct field
-by a different name, you should rename it explicitly.
-
-Change this:
+Erroneous code example:
 
 ```compile_fail,E0026
 struct Thing {
     x: u32,
-    y: u32
+    y: u32,
 }
 
 let thing = Thing { x: 0, y: 0 };
 
 match thing {
-    Thing { x, z } => {}
+    Thing { x, z } => {} // error: `Thing::z` field doesn't exist
 }
 ```
 
-To this:
+If you are using shorthand field patterns but want to refer to the struct field
+by a different name, you should rename it explicitly. Struct fields are
+identified by the name used before the colon `:` so struct patterns should
+resemble the declaration of the struct type being matched.
 
 ```
 struct Thing {
     x: u32,
-    y: u32
+    y: u32,
 }
 
 let thing = Thing { x: 0, y: 0 };
 
 match thing {
-    Thing { x, y: z } => {}
+    Thing { x, y: z } => {} // we renamed `y` to `z`
 }
 ```
 "##,
 
 E0027: r##"
-This error indicates that a pattern for a struct fails to specify a sub-pattern
-for every one of the struct's fields. Ensure that each field from the struct's
-definition is mentioned in the pattern, or use `..` to ignore unwanted fields.
+A pattern for a struct fails to specify a sub-pattern for every one of the
+struct's fields.
 
-For example:
+Erroneous code example:
 
 ```compile_fail,E0027
 struct Dog {
@@ -163,7 +149,8 @@ struct Dog {
 }
 ```
 
-This is correct (explicit):
+To fix this error, ensure that each field from the struct's definition is
+mentioned in the pattern, or use `..` to ignore unwanted fields. Example:
 
 ```
 struct Dog {
@@ -185,11 +172,9 @@ struct Dog {
 "##,
 
 E0029: r##"
-In a match expression, only numbers and characters can be matched against a
-range. This is because the compiler checks that the range is non-empty at
-compile-time, and is unable to evaluate arbitrary comparison functions. If you
-want to capture values of an orderable type between two end-points, you can use
-a guard.
+Something other than numbers and characters has been used for a range.
+
+Erroneous code example:
 
 ```compile_fail,E0029
 let string = "salutations !";
@@ -207,14 +192,18 @@ struct Dog {
     _ => {}
 }
 ```
+
+In a match expression, only numbers and characters can be matched against a
+range. This is because the compiler checks that the range is non-empty at
+compile-time, and is unable to evaluate arbitrary comparison functions. If you
+want to capture values of an orderable type between two end-points, you can use
+a guard.
 "##,
 
 E0033: r##"
-This error indicates that a pointer to a trait type cannot be implicitly
-dereferenced by a pattern. Every trait defines a type, but because the
-size of trait implementers isn't fixed, this type has no compile-time size.
-Therefore, all accesses to trait types must be through pointers. If you
-encounter this error you should try to avoid dereferencing the pointer.
+A trait type has been dereferenced.
+
+Erroneous code example:
 
 ```compile_fail,E0033
 # trait SomeTrait { fn method_one(&self){} fn method_two(&self){} }
@@ -229,6 +218,12 @@ struct Dog {
 trait_obj.method_two();
 ```
 
+A pointer to a trait type cannot be implicitly dereferenced by a pattern. Every
+trait defines a type, but because the size of trait implementers isn't fixed,
+this type has no compile-time size. Therefore, all accesses to trait types must
+be through pointers. If you encounter this error you should try to avoid
+dereferencing the pointer.
+
 You can read more about trait objects in the [Trait Objects] section of the
 Reference.
 
@@ -237,7 +232,9 @@ struct Dog {
 
 E0034: r##"
 The compiler doesn't know what method to call because more than one method
-has the same prototype. Erroneous code example:
+has the same prototype.
+
+Erroneous code example:
 
 ```compile_fail,E0034
 struct Test;
@@ -323,11 +320,9 @@ fn main() {
 "##,
 
 E0040: r##"
-It is not allowed to manually call destructors in Rust. It is also not
-necessary to do this since `drop` is called automatically whenever a value goes
-out of scope.
+It is not allowed to manually call destructors in Rust.
 
-Here's an example of this error:
+Erroneous code example:
 
 ```compile_fail,E0040
 struct Foo {
@@ -345,11 +340,33 @@ fn main() {
     x.drop(); // error: explicit use of destructor method
 }
 ```
+
+It is unnecessary to do this since `drop` is called automatically whenever a
+value goes out of scope. However, if you really need to drop a value by hand,
+you can use the `std::mem::drop` function:
+
+```
+struct Foo {
+    x: i32,
+}
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("kaboom");
+    }
+}
+
+fn main() {
+    let mut x = Foo { x: -7 };
+    drop(x); // ok!
+}
+```
 "##,
 
 E0044: r##"
 You cannot use type or const parameters on foreign items.
-Example of erroneous code:
+
+Erroneous code example:
 
 ```compile_fail,E0044
 extern { fn some_func<T>(x: T); }
@@ -365,21 +382,21 @@ fn main() {
 "##,
 
 E0045: r##"
-Rust only supports variadic parameters for interoperability with C code in its
-FFI. As such, variadic parameters can only be used with functions which are
-using the C ABI. Examples of erroneous code:
+Variadic parameters have been used on a non-C ABI function.
 
-```compile_fail
-#![feature(unboxed_closures)]
-
-extern "rust-call" { fn foo(x: u8, ...); }
+Erroneous code example:
 
-// or
+```compile_fail,E0045
+#![feature(unboxed_closures)]
 
-fn foo(x: u8, ...) {}
+extern "rust-call" {
+    fn foo(x: u8, ...); // error!
+}
 ```
 
-To fix such code, put them in an extern "C" block:
+Rust only supports variadic parameters for interoperability with C code in its
+FFI. As such, variadic parameters can only be used with functions which are
+using the C ABI. To fix such code, put them in an extern "C" block:
 
 ```
 extern "C" {
@@ -389,7 +406,9 @@ fn foo(x: u8, ...) {}
 "##,
 
 E0046: r##"
-Items are missing in a trait implementation. Erroneous code example:
+Items are missing in a trait implementation.
+
+Erroneous code example:
 
 ```compile_fail,E0046
 trait Foo {
@@ -421,11 +440,10 @@ fn foo() {} // ok!
 "##,
 
 E0049: r##"
-This error indicates that an attempted implementation of a trait method
-has the wrong number of type or const parameters.
+An attempted implementation of a trait method has the wrong number of type or
+const parameters.
 
-For example, the trait below has a method `foo` with a type parameter `T`,
-but the implementation of `foo` for the type `Bar` is missing this parameter:
+Erroneous code example:
 
 ```compile_fail,E0049
 trait Foo {
@@ -440,15 +458,31 @@ impl Foo for Bar {
     fn foo(x: bool) -> Self { Bar }
 }
 ```
+
+For example, the `Foo` trait has a method `foo` with a type parameter `T`,
+but the implementation of `foo` for the type `Bar` is missing this parameter.
+To fix this error, they must have the same type parameters:
+
+```
+trait Foo {
+    fn foo<T: Default>(x: T) -> Self;
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo<T: Default>(x: T) -> Self { // ok!
+        Bar
+    }
+}
+```
 "##,
 
 E0050: r##"
-This error indicates that an attempted implementation of a trait method
-has the wrong number of function parameters.
+An attempted implementation of a trait method has the wrong number of function
+parameters.
 
-For example, the trait below has a method `foo` with two function parameters
-(`&self` and `u8`), but the implementation of `foo` for the type `Bar` omits
-the `u8` parameter:
+Erroneous code example:
 
 ```compile_fail,E0050
 trait Foo {
@@ -463,13 +497,31 @@ impl Foo for Bar {
     fn foo(&self) -> bool { true }
 }
 ```
+
+For example, the `Foo` trait has a method `foo` with two function parameters
+(`&self` and `u8`), but the implementation of `foo` for the type `Bar` omits
+the `u8` parameter. To fix this error, they must have the same parameters:
+
+```
+trait Foo {
+    fn foo(&self, x: u8) -> bool;
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo(&self, x: u8) -> bool { // ok!
+        true
+    }
+}
+```
 "##,
 
 E0053: r##"
 The parameters of any trait method must match between a trait implementation
 and the trait definition.
 
-Here are a couple examples of this error:
+Erroneous code example:
 
 ```compile_fail,E0053
 trait Foo {
@@ -490,8 +542,9 @@ fn bar(&mut self) { }
 "##,
 
 E0054: r##"
-It is not allowed to cast to a bool. If you are trying to cast a numeric type
-to a bool, you can compare it with zero instead:
+It is not allowed to cast to a bool.
+
+Erroneous code example:
 
 ```compile_fail,E0054
 let x = 5;
@@ -500,6 +553,9 @@ fn bar(&mut self) { }
 let x_is_nonzero = x as bool;
 ```
 
+If you are trying to cast a numeric type to a bool, you can compare it with
+zero instead:
+
 ```
 let x = 5;
 
index 97f41fdc5ba463f9c83f6d6c1ff97415dcafbebc..3d42d5bb0caad5f21f3f7a13d6c92356690ee0f4 100644 (file)
@@ -39,6 +39,7 @@
 use std::hash::{Hash, Hasher};
 use std::default::Default;
 use std::{mem, slice, vec};
+use std::num::NonZeroU32;
 use std::iter::FromIterator;
 use std::rc::Rc;
 use std::cell::RefCell;
@@ -4399,7 +4400,7 @@ pub struct Stability {
     pub since: String,
     pub deprecation: Option<Deprecation>,
     pub unstable_reason: Option<String>,
-    pub issue: Option<u32>,
+    pub issue: Option<NonZeroU32>,
 }
 
 #[derive(Clone, Debug)]
@@ -4428,7 +4429,7 @@ fn clean(&self, _: &DocContext<'_>) -> Stability {
                 _ => None,
             },
             issue: match self.level {
-                attr::Unstable {issue, ..} => Some(issue),
+                attr::Unstable {issue, ..} => issue,
                 _ => None,
             }
         }
index 092fb443468483c043786407a14d2043a80be742..a038ee802105728eef0a6759fb34fb60ddcf56ad 100644 (file)
@@ -551,7 +551,7 @@ pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a,
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
-        if self.len() <= other.len() {
+        if self.len() >= other.len() {
             Union {
                 iter: self.iter().chain(other.difference(self)),
             }
index c83931a0668cfa63bc6670391b762f00d013a831..13bf6752ba2bc6baeb8fb7c1dd3ce81557f4e2be 100644 (file)
@@ -38,9 +38,6 @@
 use rustc_index::vec::Idx;
 use rustc_serialize::{self, Decoder, Encoder};
 
-#[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert_size;
-
 use std::fmt;
 
 #[cfg(test)]
@@ -1028,7 +1025,7 @@ pub struct Expr {
 
 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(Expr, 96);
+rustc_data_structures::static_assert_size!(Expr, 96);
 
 impl Expr {
     /// Returns `true` if this expression would be valid somewhere that expects a value;
index d0a31b330ab3942029e6d29f3b8e58e331793120..2b759c205f54edaf51133de8e77e91610736b7d8 100644 (file)
@@ -6,6 +6,7 @@
 use crate::sess::ParseSess;
 
 use errors::{Applicability, Handler};
+use std::num::NonZeroU32;
 use syntax_pos::hygiene::Transparency;
 use syntax_pos::{symbol::Symbol, symbol::sym, Span};
 
@@ -157,7 +158,7 @@ pub struct Stability {
 #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
 pub enum StabilityLevel {
     // Reason for the current stability level and the relevant rust-lang issue
-    Unstable { reason: Option<Symbol>, issue: u32, is_soft: bool },
+    Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
     Stable { since: Symbol },
 }
 
@@ -394,18 +395,28 @@ macro_rules! get_meta {
 
                     match (feature, reason, issue) {
                         (Some(feature), reason, Some(issue)) => {
+                            let issue = match &*issue.as_str() {
+                                // FIXME(rossmacarthur): remove "0" because "none" should be used
+                                // See #41260
+                                "none" | "0" => None,
+                                issue => {
+                                    if let Ok(num) = issue.parse() {
+                                        NonZeroU32::new(num)
+                                    } else {
+                                        span_err!(
+                                            diagnostic,
+                                            attr.span,
+                                            E0545,
+                                            "incorrect 'issue'"
+                                        );
+                                        continue
+                                    }
+                                }
+                            };
                             stab = Some(Stability {
                                 level: Unstable {
                                     reason,
-                                    issue: {
-                                        if let Ok(issue) = issue.as_str().parse() {
-                                            issue
-                                        } else {
-                                            span_err!(diagnostic, attr.span, E0545,
-                                                      "incorrect 'issue'");
-                                            continue
-                                        }
-                                    },
+                                    issue,
                                     is_soft,
                                 },
                                 feature,
index d59d0f0e28e9b2aa9028a8101bb7d6f98ba3b7e3..2819ee273d9f042029956ef097f4d2ed122b3f0e 100644 (file)
@@ -207,10 +207,10 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`.
     (active, allocator_internals, "1.20.0", None, None),
 
-    // no-tracking-issue-end
-
     /// Added for testing E0705; perma-unstable.
-    (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)),
+    (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+
+    // no-tracking-issue-end
 
     // -------------------------------------------------------------------------
     // feature-group-end: internal feature gates
index 4742e01d7f4eac2e3005bd266234d306e126dbbe..3bf1e24bf12796d8734d183a537fd7963f231cf8 100644 (file)
@@ -18,6 +18,7 @@
 use log::debug;
 
 use std::env;
+use std::num::NonZeroU32;
 
 #[derive(Copy, Clone, Debug)]
 pub enum Stability {
@@ -55,25 +56,28 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
     PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
 }
 
-fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
+fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
         // FIXME (#28244): enforce that active features have issue numbers
-        // assert!(info.issue.is_some())
-        info.issue
+        // assert!(info.issue().is_some())
+        info.issue()
     } else {
         // search in Accepted, Removed, or Stable Removed features
-        let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
+        let found = ACCEPTED_FEATURES
+            .iter()
+            .chain(REMOVED_FEATURES)
+            .chain(STABLE_REMOVED_FEATURES)
             .find(|t| t.name == feature);
         match found {
-            Some(&Feature { issue, .. }) => issue,
-            None => panic!("Feature `{}` is not declared anywhere", feature),
+            Some(found) => found.issue(),
+            None => panic!("feature `{}` is not declared anywhere", feature),
         }
     }
 }
 
 pub enum GateIssue {
     Language,
-    Library(Option<u32>)
+    Library(Option<NonZeroU32>)
 }
 
 #[derive(Debug, Copy, Clone, PartialEq)]
@@ -126,14 +130,11 @@ fn leveled_feature_err<'a, S: Into<MultiSpan>>(
         GateStrength::Soft => diag.struct_span_warn(span, explain),
     };
 
-    match issue {
-        None | Some(0) => {}  // We still accept `0` as a stand-in for backwards compatibility
-        Some(n) => {
-            err.note(&format!(
-                "for more information, see https://github.com/rust-lang/rust/issues/{}",
-                n,
-            ));
-        }
+    if let Some(n) = issue {
+        err.note(&format!(
+            "for more information, see https://github.com/rust-lang/rust/issues/{}",
+            n,
+        ));
     }
 
     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
index ba970618c0e139d35ff7dfe5d1a3c79de18a6bac..c4418c0f0f632b26cf26ec0e1e900ca0868d76c8 100644 (file)
@@ -18,8 +18,9 @@
 mod builtin_attrs;
 mod check;
 
-use std::fmt;
 use crate::{edition::Edition, symbol::Symbol};
+use std::fmt;
+use std::num::NonZeroU32;
 use syntax_pos::Span;
 
 #[derive(Clone, Copy)]
@@ -46,11 +47,17 @@ pub struct Feature {
     state: State,
     name: Symbol,
     since: &'static str,
-    issue: Option<u32>,
+    issue: Option<u32>,  // FIXME: once #58732 is done make this an Option<NonZeroU32>
     edition: Option<Edition>,
     description: &'static str,
 }
 
+impl Feature {
+    fn issue(&self) -> Option<NonZeroU32> {
+        self.issue.and_then(|i| NonZeroU32::new(i))
+    }
+}
+
 pub use active::{Features, INCOMPLETE_FEATURES};
 pub use builtin_attrs::{
     AttributeGate, AttributeType, GatedCfg,
index c70e34427037c3287c74a2c5d3533b584cc983b2..ab798e93d67fc009bb2208b86c5d400f44e9ae76 100644 (file)
@@ -14,8 +14,6 @@
 
 use std::fmt;
 use std::mem;
-#[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::Lrc;
 
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
@@ -261,7 +259,7 @@ pub enum TokenKind {
 
 // `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(TokenKind, 16);
+rustc_data_structures::static_assert_size!(TokenKind, 16);
 
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
 pub struct Token {
index 4d08d0974c133a3965139b0d435ab8431ac6f0ba..2201f1ed6caca46228936efeef4ef3c135d183ad 100644 (file)
@@ -16,8 +16,6 @@
 use crate::token::{self, DelimToken, Token, TokenKind};
 
 use syntax_pos::{Span, DUMMY_SP};
-#[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::Lrc;
 use smallvec::{SmallVec, smallvec};
 
@@ -129,7 +127,7 @@ pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
 
 // `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(TokenStream, 8);
+rustc_data_structures::static_assert_size!(TokenStream, 8);
 
 #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum IsJoint {
index 792c97d8508fe4a8418e68c73b72bb368d4cba12..fbded7dc130eb3a6a72798e6c20295ac27b5af4e 100644 (file)
@@ -92,10 +92,12 @@ pub fn inject(sess: &ParseSess,
 impl<'a> CollectProcMacros<'a> {
     fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
         if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() {
-            self.handler.span_err(sp,
-                                  "`proc-macro` crate types cannot \
-                                   export any items other than functions \
-                                   tagged with `#[proc_macro_derive]` currently");
+            self.handler.span_err(
+                sp,
+                "`proc-macro` crate types currently cannot export any items other \
+                    than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, \
+                    or `#[proc_macro_attribute]`",
+            );
         }
     }
 
index 7f15f02d4d37bb3e96a382d16c8b45f6dddb3335..9acb4ad9cbbe5e4c3f8c4616de1b5546c5f8c11b 100644 (file)
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _]` not covered
+error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _, ..]` not covered
   --> $DIR/const_let_refutable.rs:3:16
    |
 LL | const fn slice([a, b]: &[i32]) -> i32 {
-   |                ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _]` not covered
+   |                ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _, ..]` not covered
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
   --> $DIR/const_let_refutable.rs:4:5
diff --git a/src/test/ui/feature-gate/unstable-attribute-allow-issue-none.rs b/src/test/ui/feature-gate/unstable-attribute-allow-issue-none.rs
new file mode 100644 (file)
index 0000000..3ce9de3
--- /dev/null
@@ -0,0 +1,13 @@
+// Check that an issue value can be explicitly set to "none" instead of "0"
+#![crate_type = "lib"]
+#![feature(staged_api)]
+#![stable(feature = "stable_test_feature", since = "1.0.0")]
+
+#[unstable(feature = "unstable_test_feature", issue = "0")]
+fn unstable_issue_0() {}
+
+#[unstable(feature = "unstable_test_feature", issue = "none")]
+fn unstable_issue_none() {}
+
+#[unstable(feature = "unstable_test_feature", issue = "something")] //~ ERROR incorrect 'issue'
+fn unstable_issue_not_allowed() {}
diff --git a/src/test/ui/feature-gate/unstable-attribute-allow-issue-none.stderr b/src/test/ui/feature-gate/unstable-attribute-allow-issue-none.stderr
new file mode 100644 (file)
index 0000000..fc031f5
--- /dev/null
@@ -0,0 +1,8 @@
+error[E0545]: incorrect 'issue'
+  --> $DIR/unstable-attribute-allow-issue-none.rs:12:1
+   |
+LL | #[unstable(feature = "unstable_test_feature", issue = "something")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/pattern/slice-pattern-const-2.rs b/src/test/ui/pattern/slice-pattern-const-2.rs
deleted file mode 100644 (file)
index a36c550..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#![deny(unreachable_patterns)]
-
-fn main() {
-    let s = &[0x00; 4][..]; //Slice of any value
-    const MAGIC_TEST: &[u32] = &[4, 5, 6, 7]; //Const slice to pattern match with
-    match s {
-        MAGIC_TEST => (),
-        [0x00, 0x00, 0x00, 0x00] => (),
-        [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
-        _ => (),
-    }
-    match s {
-        [0x00, 0x00, 0x00, 0x00] => (),
-        MAGIC_TEST => (),
-        [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
-        _ => (),
-    }
-    match s {
-        [0x00, 0x00, 0x00, 0x00] => (),
-        [4, 5, 6, 7] => (),
-        MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not
-        _ => (),
-    }
-    const FOO: [u32; 1] = [4];
-    match [99] {
-        [0x00] => (),
-        [4] => (),
-        FOO => (), //~ ERROR unreachable pattern
-        _ => (),
-    }
-}
diff --git a/src/test/ui/pattern/slice-pattern-const-2.stderr b/src/test/ui/pattern/slice-pattern-const-2.stderr
deleted file mode 100644 (file)
index 0c74012..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: unreachable pattern
-  --> $DIR/slice-pattern-const-2.rs:28:9
-   |
-LL |         FOO => (),
-   |         ^^^
-   |
-note: lint level defined here
-  --> $DIR/slice-pattern-const-2.rs:1:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/pattern/slice-pattern-const-3.rs b/src/test/ui/pattern/slice-pattern-const-3.rs
deleted file mode 100644 (file)
index 8805c43..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#![deny(unreachable_patterns)]
-
-fn main() {
-    let s = &["0x00"; 4][..]; //Slice of any value
-    const MAGIC_TEST: &[&str] = &["4", "5", "6", "7"]; //Const slice to pattern match with
-    match s {
-        MAGIC_TEST => (),
-        ["0x00", "0x00", "0x00", "0x00"] => (),
-        ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not
-        _ => (),
-    }
-    match s {
-        ["0x00", "0x00", "0x00", "0x00"] => (),
-        MAGIC_TEST => (),
-        ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not
-        _ => (),
-    }
-    match s {
-        ["0x00", "0x00", "0x00", "0x00"] => (),
-        ["4", "5", "6", "7"] => (),
-        MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not
-        _ => (),
-    }
-    const FOO: [&str; 1] = ["boo"];
-    match ["baa"] {
-        ["0x00"] => (),
-        ["boo"] => (),
-        FOO => (), //~ ERROR unreachable pattern
-        _ => (),
-    }
-}
diff --git a/src/test/ui/pattern/slice-pattern-const-3.stderr b/src/test/ui/pattern/slice-pattern-const-3.stderr
deleted file mode 100644 (file)
index eab4fc3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: unreachable pattern
-  --> $DIR/slice-pattern-const-3.rs:28:9
-   |
-LL |         FOO => (),
-   |         ^^^
-   |
-note: lint level defined here
-  --> $DIR/slice-pattern-const-3.rs:1:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/pattern/slice-pattern-const.rs b/src/test/ui/pattern/slice-pattern-const.rs
deleted file mode 100644 (file)
index f0a0451..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#![deny(unreachable_patterns)]
-
-fn main() {
-    let s = &[0x00; 4][..]; //Slice of any value
-    const MAGIC_TEST: &[u8] = b"TEST"; //Const slice to pattern match with
-    match s {
-        MAGIC_TEST => (),
-        [0x00, 0x00, 0x00, 0x00] => (),
-        [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
-        _ => (),
-    }
-    match s {
-        [0x00, 0x00, 0x00, 0x00] => (),
-        MAGIC_TEST => (),
-        [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
-        _ => (),
-    }
-    match s {
-        [0x00, 0x00, 0x00, 0x00] => (),
-        [84, 69, 83, 84] => (),
-        MAGIC_TEST => (), //~ ERROR unreachable pattern
-        _ => (),
-    }
-    const FOO: [u8; 1] = [4];
-    match [99] {
-        [0x00] => (),
-        [4] => (),
-        FOO => (), //~ ERROR unreachable pattern
-        _ => (),
-    }
-    const BAR: &[u8; 1] = &[4];
-    match &[99] {
-        [0x00] => (),
-        [4] => (),
-        BAR => (), //~ ERROR unreachable pattern
-        b"a" => (),
-        _ => (),
-    }
-
-    const BOO: &[u8; 0] = &[];
-    match &[] {
-        [] => (),
-        BOO => (), //~ ERROR unreachable pattern
-        b"" => (), //~ ERROR unreachable pattern
-        _ => (), //~ ERROR unreachable pattern
-    }
-}
diff --git a/src/test/ui/pattern/slice-pattern-const.stderr b/src/test/ui/pattern/slice-pattern-const.stderr
deleted file mode 100644 (file)
index 2dd10a0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:9:9
-   |
-LL |         [84, 69, 83, 84] => (),
-   |         ^^^^^^^^^^^^^^^^
-   |
-note: lint level defined here
-  --> $DIR/slice-pattern-const.rs:1:9
-   |
-LL | #![deny(unreachable_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:15:9
-   |
-LL |         [84, 69, 83, 84] => (),
-   |         ^^^^^^^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:21:9
-   |
-LL |         MAGIC_TEST => (),
-   |         ^^^^^^^^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:28:9
-   |
-LL |         FOO => (),
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:35:9
-   |
-LL |         BAR => (),
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:43:9
-   |
-LL |         BOO => (),
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:44:9
-   |
-LL |         b"" => (),
-   |         ^^^
-
-error: unreachable pattern
-  --> $DIR/slice-pattern-const.rs:45:9
-   |
-LL |         _ => (),
-   |         ^
-
-error: aborting due to 8 previous errors
-
index d53e2e25b3dbd44300dfe8e687958f36604c4193..6e52072e3bfec7f91f6ec8f34307b0c09d289b08 100644 (file)
@@ -6,11 +6,11 @@ LL |     match buf {
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 3 more not covered
+error[E0004]: non-exhaustive patterns: `&[..]` not covered
   --> $DIR/match-byte-array-patterns-2.rs:10:11
    |
 LL |     match buf {
-   |           ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 3 more not covered
+   |           ^^^ pattern `&[..]` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
index afbeb61e4415af0cd799b08d37fbc2f8c7f24f7b..af7fd53a1f1e916dc505338cf469b4183ae8a094 100644 (file)
@@ -2,7 +2,7 @@
 
 fn check(list: &[Option<()>]) {
     match list {
-    //~^ ERROR `&[_, Some(_), None, _]` not covered
+    //~^ ERROR `&[_, Some(_), .., None, _]` not covered
         &[] => {},
         &[_] => {},
         &[_, _] => {},
index 24769db34c9322f252d1917967674717fc3448bb..72ae5d5fe3b33e172a1a499ee984a3d1ecc2c149 100644 (file)
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `&[_, Some(_), None, _]` not covered
+error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered
   --> $DIR/match-slice-patterns.rs:4:11
    |
 LL |     match list {
-   |           ^^^^ pattern `&[_, Some(_), None, _]` not covered
+   |           ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
index 0e5a9203c5f80ac5f532dc8d61a6f4882c2791ce..bfca5352353a7c0c6ad724bc0bb3e8d438f5a391 100644 (file)
@@ -44,7 +44,7 @@ fn main() {
     }
     let vec = vec![0.5f32];
     let vec: &[f32] = &vec;
-    match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
+    match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _, ..]` not covered
         [0.1, 0.2, 0.3] => (),
         [0.1, 0.2] => (),
         [0.1] => (),
index 5dba05e16427a8df24a27d5308bbe316b5d2c2c3..577867e4e712294025aaff2a88e562aa05f35538 100644 (file)
@@ -66,11 +66,11 @@ LL |     match *vec {
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: `[_, _, _, _]` not covered
+error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
   --> $DIR/non-exhaustive-match.rs:47:11
    |
 LL |     match *vec {
-   |           ^^^^ pattern `[_, _, _, _]` not covered
+   |           ^^^^ pattern `[_, _, _, _, ..]` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs
new file mode 100644 (file)
index 0000000..a36c550
--- /dev/null
@@ -0,0 +1,31 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+    let s = &[0x00; 4][..]; //Slice of any value
+    const MAGIC_TEST: &[u32] = &[4, 5, 6, 7]; //Const slice to pattern match with
+    match s {
+        MAGIC_TEST => (),
+        [0x00, 0x00, 0x00, 0x00] => (),
+        [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    match s {
+        [0x00, 0x00, 0x00, 0x00] => (),
+        MAGIC_TEST => (),
+        [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    match s {
+        [0x00, 0x00, 0x00, 0x00] => (),
+        [4, 5, 6, 7] => (),
+        MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    const FOO: [u32; 1] = [4];
+    match [99] {
+        [0x00] => (),
+        [4] => (),
+        FOO => (), //~ ERROR unreachable pattern
+        _ => (),
+    }
+}
diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr
new file mode 100644 (file)
index 0000000..0c74012
--- /dev/null
@@ -0,0 +1,14 @@
+error: unreachable pattern
+  --> $DIR/slice-pattern-const-2.rs:28:9
+   |
+LL |         FOO => (),
+   |         ^^^
+   |
+note: lint level defined here
+  --> $DIR/slice-pattern-const-2.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs
new file mode 100644 (file)
index 0000000..8805c43
--- /dev/null
@@ -0,0 +1,31 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+    let s = &["0x00"; 4][..]; //Slice of any value
+    const MAGIC_TEST: &[&str] = &["4", "5", "6", "7"]; //Const slice to pattern match with
+    match s {
+        MAGIC_TEST => (),
+        ["0x00", "0x00", "0x00", "0x00"] => (),
+        ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    match s {
+        ["0x00", "0x00", "0x00", "0x00"] => (),
+        MAGIC_TEST => (),
+        ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    match s {
+        ["0x00", "0x00", "0x00", "0x00"] => (),
+        ["4", "5", "6", "7"] => (),
+        MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not
+        _ => (),
+    }
+    const FOO: [&str; 1] = ["boo"];
+    match ["baa"] {
+        ["0x00"] => (),
+        ["boo"] => (),
+        FOO => (), //~ ERROR unreachable pattern
+        _ => (),
+    }
+}
diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr
new file mode 100644 (file)
index 0000000..eab4fc3
--- /dev/null
@@ -0,0 +1,14 @@
+error: unreachable pattern
+  --> $DIR/slice-pattern-const-3.rs:28:9
+   |
+LL |         FOO => (),
+   |         ^^^
+   |
+note: lint level defined here
+  --> $DIR/slice-pattern-const-3.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const.rs b/src/test/ui/pattern/usefulness/slice-pattern-const.rs
new file mode 100644 (file)
index 0000000..f0a0451
--- /dev/null
@@ -0,0 +1,47 @@
+#![deny(unreachable_patterns)]
+
+fn main() {
+    let s = &[0x00; 4][..]; //Slice of any value
+    const MAGIC_TEST: &[u8] = b"TEST"; //Const slice to pattern match with
+    match s {
+        MAGIC_TEST => (),
+        [0x00, 0x00, 0x00, 0x00] => (),
+        [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
+        _ => (),
+    }
+    match s {
+        [0x00, 0x00, 0x00, 0x00] => (),
+        MAGIC_TEST => (),
+        [84, 69, 83, 84] => (), //~ ERROR unreachable pattern
+        _ => (),
+    }
+    match s {
+        [0x00, 0x00, 0x00, 0x00] => (),
+        [84, 69, 83, 84] => (),
+        MAGIC_TEST => (), //~ ERROR unreachable pattern
+        _ => (),
+    }
+    const FOO: [u8; 1] = [4];
+    match [99] {
+        [0x00] => (),
+        [4] => (),
+        FOO => (), //~ ERROR unreachable pattern
+        _ => (),
+    }
+    const BAR: &[u8; 1] = &[4];
+    match &[99] {
+        [0x00] => (),
+        [4] => (),
+        BAR => (), //~ ERROR unreachable pattern
+        b"a" => (),
+        _ => (),
+    }
+
+    const BOO: &[u8; 0] = &[];
+    match &[] {
+        [] => (),
+        BOO => (), //~ ERROR unreachable pattern
+        b"" => (), //~ ERROR unreachable pattern
+        _ => (), //~ ERROR unreachable pattern
+    }
+}
diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const.stderr
new file mode 100644 (file)
index 0000000..2dd10a0
--- /dev/null
@@ -0,0 +1,56 @@
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:9:9
+   |
+LL |         [84, 69, 83, 84] => (),
+   |         ^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/slice-pattern-const.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:15:9
+   |
+LL |         [84, 69, 83, 84] => (),
+   |         ^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:21:9
+   |
+LL |         MAGIC_TEST => (),
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:28:9
+   |
+LL |         FOO => (),
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:35:9
+   |
+LL |         BAR => (),
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:43:9
+   |
+LL |         BOO => (),
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:44:9
+   |
+LL |         b"" => (),
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/slice-pattern-const.rs:45:9
+   |
+LL |         _ => (),
+   |         ^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
new file mode 100644 (file)
index 0000000..86cdf16
--- /dev/null
@@ -0,0 +1,75 @@
+#![feature(slice_patterns)]
+
+fn main() {
+    let s: &[bool] = &[true; 0];
+    let s1: &[bool; 1] = &[false; 1];
+    let s2: &[bool; 2] = &[false; 2];
+    let s3: &[bool; 3] = &[false; 3];
+
+    match s1 {
+        [true, ..] => {}
+        [.., false] => {}
+    }
+    match s2 {
+    //~^ ERROR `&[false, true]` not covered
+        [true, ..] => {}
+        [.., false] => {}
+    }
+    match s3 {
+    //~^ ERROR `&[false, _, true]` not covered
+        [true, ..] => {}
+        [.., false] => {}
+    }
+    match s {
+    //~^ ERROR `&[false, .., true]` not covered
+        [] => {}
+        [true, ..] => {}
+        [.., false] => {}
+    }
+
+    match s3 {
+    //~^ ERROR `&[false, _, _]` not covered
+        [true, .., true] => {}
+    }
+    match s {
+    //~^ ERROR `&[_, ..]` not covered
+        [] => {}
+    }
+    match s {
+    //~^ ERROR `&[_, _, ..]` not covered
+        [] => {}
+        [_] => {}
+    }
+    match s {
+    //~^ ERROR `&[false, ..]` not covered
+        [] => {}
+        [true, ..] => {}
+    }
+    match s {
+    //~^ ERROR `&[false, _, ..]` not covered
+        [] => {}
+        [_] => {}
+        [true, ..] => {}
+    }
+    match s {
+    //~^ ERROR `&[_, .., false]` not covered
+        [] => {}
+        [_] => {}
+        [.., true] => {}
+    }
+
+    match s {
+    //~^ ERROR `&[_, _, .., true]` not covered
+        [] => {}
+        [_] => {}
+        [_, _] => {}
+        [.., false] => {}
+    }
+    match s {
+    //~^ ERROR `&[true, _, .., _]` not covered
+        [] => {}
+        [_] => {}
+        [_, _] => {}
+        [false, .., false] => {}
+    }
+}
diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
new file mode 100644 (file)
index 0000000..1391b52
--- /dev/null
@@ -0,0 +1,91 @@
+error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:13:11
+   |
+LL |     match s2 {
+   |           ^^ pattern `&[false, true]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[false, _, true]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:18:11
+   |
+LL |     match s3 {
+   |           ^^ pattern `&[false, _, true]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:23:11
+   |
+LL |     match s {
+   |           ^ pattern `&[false, .., true]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[false, _, _]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:30:11
+   |
+LL |     match s3 {
+   |           ^^ pattern `&[false, _, _]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:34:11
+   |
+LL |     match s {
+   |           ^ pattern `&[_, ..]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:38:11
+   |
+LL |     match s {
+   |           ^ pattern `&[_, _, ..]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:43:11
+   |
+LL |     match s {
+   |           ^ pattern `&[false, ..]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:48:11
+   |
+LL |     match s {
+   |           ^ pattern `&[false, _, ..]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:54:11
+   |
+LL |     match s {
+   |           ^ pattern `&[_, .., false]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:61:11
+   |
+LL |     match s {
+   |           ^ pattern `&[_, _, .., true]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
+  --> $DIR/slice-patterns-exhaustiveness.rs:68:11
+   |
+LL |     match s {
+   |           ^ pattern `&[true, _, .., _]` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs b/src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs
new file mode 100644 (file)
index 0000000..3b716ba
--- /dev/null
@@ -0,0 +1,27 @@
+// check-pass
+#![feature(slice_patterns)]
+
+fn main() {
+    let s: &[bool] = &[true; 0];
+    let s0: &[bool; 0] = &[];
+    let s1: &[bool; 1] = &[false; 1];
+    let s2: &[bool; 2] = &[false; 2];
+
+    let [] = s0;
+    let [_] = s1;
+    let [_, _] = s2;
+
+    let [..] = s;
+    let [..] = s0;
+    let [..] = s1;
+    let [..] = s2;
+
+    let [_, ..] = s1;
+    let [.., _] = s1;
+    let [_, ..] = s2;
+    let [.., _] = s2;
+
+    let [_, _, ..] = s2;
+    let [_, .., _] = s2;
+    let [.., _, _] = s2;
+}
diff --git a/src/test/ui/pattern/usefulness/slice-patterns-reachability.rs b/src/test/ui/pattern/usefulness/slice-patterns-reachability.rs
new file mode 100644 (file)
index 0000000..35d9dc9
--- /dev/null
@@ -0,0 +1,26 @@
+#![feature(slice_patterns)]
+#![deny(unreachable_patterns)]
+
+fn main() {
+    let s: &[bool] = &[true; 0];
+
+    match s {
+        [true, ..] => {}
+        [true, ..] => {} //~ ERROR unreachable pattern
+        [true] => {} //~ ERROR unreachable pattern
+        [..] => {}
+    }
+    match s {
+        [.., true] => {}
+        [.., true] => {} //~ ERROR unreachable pattern
+        [true] => {} //~ ERROR unreachable pattern
+        [..] => {}
+    }
+    match s {
+        [false, .., true] => {}
+        [false, .., true] => {} //~ ERROR unreachable pattern
+        [false, true] => {} //~ ERROR unreachable pattern
+        [false] => {}
+        [..] => {}
+    }
+}
diff --git a/src/test/ui/pattern/usefulness/slice-patterns-reachability.stderr b/src/test/ui/pattern/usefulness/slice-patterns-reachability.stderr
new file mode 100644 (file)
index 0000000..333ce17
--- /dev/null
@@ -0,0 +1,44 @@
+error: unreachable pattern
+  --> $DIR/slice-patterns-reachability.rs:9:9
+   |
+LL |         [true, ..] => {}
+   |         ^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/slice-patterns-reachability.rs:2:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-patterns-reachability.rs:10:9
+   |
+LL |         [true] => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-patterns-reachability.rs:15:9
+   |
+LL |         [.., true] => {}
+   |         ^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-patterns-reachability.rs:16:9
+   |
+LL |         [true] => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-patterns-reachability.rs:21:9
+   |
+LL |         [false, .., true] => {}
+   |         ^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/slice-patterns-reachability.rs:22:9
+   |
+LL |         [false, true] => {}
+   |         ^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
index 2f81921358dfe9a2980996b2f1331973f7fa7279..0ecbdf98dd31cb3b8e9870893cae2d6d12204620 100644 (file)
@@ -1,22 +1,22 @@
-error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently
+error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
   --> $DIR/exports.rs:7:1
    |
 LL | pub fn a() {}
    | ^^^^^^^^^^^^^
 
-error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently
+error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
   --> $DIR/exports.rs:8:1
    |
 LL | pub struct B;
    | ^^^^^^^^^^^^^
 
-error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently
+error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
   --> $DIR/exports.rs:9:1
    |
 LL | pub enum C {}
    | ^^^^^^^^^^^^^
 
-error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently
+error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
   --> $DIR/exports.rs:10:1
    |
 LL | pub mod d {}
index 7544245ff6795f3d476c2ab06e4c226f8c940e06..54cf333a45b137bff6cd1bd4e40d78d717346c8b 100644 (file)
@@ -5,7 +5,7 @@
 
 extern crate proc_macro;
 
-pub mod a { //~ `proc-macro` crate types cannot export any items
+pub mod a { //~ `proc-macro` crate types currently cannot export any items
     use proc_macro::TokenStream;
 
     #[proc_macro_derive(B)]
index 66fa499d33bb2546820d0f9feda4b031c32b37aa..3b69b7875bde093a1820429348494fa5c2e5529c 100644 (file)
@@ -1,4 +1,4 @@
-error: `proc-macro` crate types cannot export any items other than functions tagged with `#[proc_macro_derive]` currently
+error: `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
   --> $DIR/pub-at-crate-root.rs:8:1
    |
 LL | / pub mod a {
index a49344e45cec652775d6737f3b8c178d9477e0fa..7af6075262c6db9e75b3ec2ea39ef04d0ac86022 100644 (file)
@@ -30,11 +30,11 @@ LL |     let _ = match x {};
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: `&[_]` not covered
+error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   --> $DIR/uninhabited-matches-feature-gated.rs:21:19
    |
 LL |     let _ = match x {
-   |                   ^ pattern `&[_]` not covered
+   |                   ^ pattern `&[_, ..]` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
index 3abdd2f1ced4cf3a44c7de88c5e39b3bb5037c4d..86b8643586aa39f36fb7a02e98c8d64d31415e70 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3abdd2f1ced4cf3a44c7de88c5e39b3bb5037c4d
+Subproject commit 86b8643586aa39f36fb7a02e98c8d64d31415e70