]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #64895 - davidtwco:issue-64130-async-error-definition, r=nikomatsakis
authorMazdak Farrokhzad <twingoow@gmail.com>
Tue, 1 Oct 2019 07:55:31 +0000 (09:55 +0200)
committerGitHub <noreply@github.com>
Tue, 1 Oct 2019 07:55:31 +0000 (09:55 +0200)
async/await: improve not-send errors

cc #64130.

```
note: future does not implement `std::marker::Send` because this value is used across an await
  --> $DIR/issue-64130-non-send-future-diags.rs:15:5
   |
LL |     let g = x.lock().unwrap();
   |         - has type `std::sync::MutexGuard<'_, u32>`
LL |     baz().await;
   |     ^^^^^^^^^^^ await occurs here, with `g` maybe used later
LL | }
   | - `g` is later dropped here
```

r? @nikomatsakis

290 files changed:
Cargo.lock
README.md
src/ci/docker/dist-x86_64-linux/build-curl.sh
src/liballoc/tests/vec.rs
src/liballoc/vec.rs
src/libcore/mem/mod.rs
src/libcore/option.rs
src/libcore/slice/mod.rs
src/librustc/Cargo.toml
src/librustc/arena.rs
src/librustc/dep_graph/graph.rs
src/librustc/dep_graph/serialized.rs
src/librustc/hir/def_id.rs
src/librustc/hir/lowering.rs
src/librustc/hir/lowering/expr.rs
src/librustc/hir/map/collector.rs
src/librustc/hir/map/definitions.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/ich/impls_syntax.rs
src/librustc/infer/canonical/canonicalizer.rs
src/librustc/infer/canonical/mod.rs
src/librustc/infer/canonical/query_response.rs
src/librustc/infer/lexical_region_resolve/mod.rs
src/librustc/infer/region_constraints/mod.rs
src/librustc/middle/intrinsicck.rs
src/librustc/middle/region.rs
src/librustc/mir/cache.rs
src/librustc/mir/interpret/mod.rs
src/librustc/mir/interpret/value.rs
src/librustc/mir/mod.rs
src/librustc/mir/traversal.rs
src/librustc/query/mod.rs
src/librustc/session/config.rs
src/librustc/traits/select.rs
src/librustc/ty/context.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc/ty/query/mod.rs
src/librustc/ty/query/on_disk_cache.rs
src/librustc/ty/relate.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
src/librustc_codegen_llvm/debuginfo/mod.rs
src/librustc_codegen_llvm/lib.rs
src/librustc_codegen_ssa/Cargo.toml
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/base.rs
src/librustc_codegen_ssa/mir/analyze.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_codegen_ssa/mir/constant.rs
src/librustc_codegen_ssa/mir/mod.rs
src/librustc_codegen_ssa/traits/debuginfo.rs
src/librustc_data_structures/Cargo.toml
src/librustc_data_structures/bit_set.rs [deleted file]
src/librustc_data_structures/bit_set/tests.rs [deleted file]
src/librustc_data_structures/graph/dominators/mod.rs
src/librustc_data_structures/graph/implementation/mod.rs
src/librustc_data_structures/graph/iterate/mod.rs
src/librustc_data_structures/graph/mod.rs
src/librustc_data_structures/graph/scc/mod.rs
src/librustc_data_structures/graph/vec_graph/mod.rs
src/librustc_data_structures/indexed_vec.rs [deleted file]
src/librustc_data_structures/lib.rs
src/librustc_data_structures/obligation_forest/mod.rs
src/librustc_data_structures/stable_hasher.rs
src/librustc_data_structures/transitive_relation.rs
src/librustc_data_structures/vec_linked_list.rs
src/librustc_data_structures/work_queue.rs
src/librustc_index/Cargo.toml [new file with mode: 0644]
src/librustc_index/bit_set.rs [new file with mode: 0644]
src/librustc_index/bit_set/tests.rs [new file with mode: 0644]
src/librustc_index/lib.rs [new file with mode: 0644]
src/librustc_index/vec.rs [new file with mode: 0644]
src/librustc_interface/passes.rs
src/librustc_lint/Cargo.toml
src/librustc_lint/types.rs
src/librustc_macros/src/lib.rs
src/librustc_metadata/Cargo.toml
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/schema.rs
src/librustc_mir/Cargo.toml
src/librustc_mir/borrow_check/borrow_set.rs
src/librustc_mir/borrow_check/conflict_errors.rs
src/librustc_mir/borrow_check/flows.rs
src/librustc_mir/borrow_check/location.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/mutability_errors.rs
src/librustc_mir/borrow_check/nll/constraints/graph.rs
src/librustc_mir/borrow_check/nll/constraints/mod.rs
src/librustc_mir/borrow_check/nll/facts.rs
src/librustc_mir/borrow_check/nll/member_constraints.rs
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/values.rs
src/librustc_mir/borrow_check/nll/renumber.rs
src/librustc_mir/borrow_check/nll/type_check/input_output.rs
src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/borrow_check/nll/universal_regions.rs
src/librustc_mir/build/expr/as_place.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/dataflow/at_location.rs
src/librustc_mir/dataflow/generic.rs
src/librustc_mir/dataflow/generic/graphviz.rs [new file with mode: 0644]
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/impls/indirect_mutation.rs
src/librustc_mir/dataflow/impls/mod.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/dataflow/move_paths/mod.rs
src/librustc_mir/error_codes.rs
src/librustc_mir/hair/cx/block.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/snapshot.rs
src/librustc_mir/lints.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/add_call_guards.rs
src/librustc_mir/transform/check_consts/qualifs.rs
src/librustc_mir/transform/check_consts/resolver.rs
src/librustc_mir/transform/check_consts/validation.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/instcombine.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/remove_noop_landing_pads.rs
src/librustc_mir/transform/rustc_peek.rs
src/librustc_mir/transform/simplify.rs
src/librustc_mir/transform/uniform_array_move_out.rs
src/librustc_mir/util/aggregate.rs
src/librustc_mir/util/def_use.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_mir/util/graphviz.rs
src/librustc_mir/util/liveness.rs
src/librustc_mir/util/patch.rs
src/librustc_mir/util/pretty.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_target/Cargo.toml
src/librustc_target/abi/mod.rs
src/librustc_typeck/Cargo.toml
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/expr.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/error_codes.rs
src/librustdoc/clean/mod.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/libsyntax/Cargo.toml
src/libsyntax/ast.rs
src/libsyntax/attr/mod.rs
src/libsyntax/config.rs
src/libsyntax/error_codes.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/mbe/macro_parser.rs
src/libsyntax/feature_gate/accepted.rs
src/libsyntax/feature_gate/active.rs
src/libsyntax/lib.rs
src/libsyntax/mut_visit.rs
src/libsyntax/parse/attr.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/parser/item.rs
src/libsyntax/parse/parser/pat.rs
src/libsyntax/parse/parser/path.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax_ext/cmdline_attrs.rs
src/libsyntax_ext/test_harness.rs
src/libsyntax_pos/Cargo.toml
src/libsyntax_pos/symbol.rs
src/libtest/formatters/mod.rs
src/libtest/lib.rs
src/libtest/tests.rs
src/test/ui-fulldeps/newtype_index.rs
src/test/ui/abi/macros/macros-in-extern.rs [deleted file]
src/test/ui/abi/macros/macros-in-extern.stderr [deleted file]
src/test/ui/abi/proc-macro/auxiliary/test-macros.rs [deleted file]
src/test/ui/abi/proc-macro/macros-in-extern.rs [deleted file]
src/test/ui/abi/proc-macro/macros-in-extern.stderr [deleted file]
src/test/ui/cfg/cfg_stmt_expr.rs
src/test/ui/check-static-values-constraints.stderr
src/test/ui/const-generics/slice-const-param-mismatch.rs [new file with mode: 0644]
src/test/ui/const-generics/slice-const-param-mismatch.stderr [new file with mode: 0644]
src/test/ui/const-generics/slice-const-param.rs [new file with mode: 0644]
src/test/ui/const-generics/slice-const-param.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/const_let.stderr
src/test/ui/consts/issue-64662.rs [new file with mode: 0644]
src/test/ui/consts/issue-64662.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_fn.stderr
src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
src/test/ui/deprecation/deprecation-sanity.stderr
src/test/ui/empty/empty-struct-braces-expr.stderr
src/test/ui/empty/empty-struct-braces-pat-1.stderr
src/test/ui/empty/empty-struct-braces-pat-2.stderr
src/test/ui/empty/empty-struct-braces-pat-3.stderr
src/test/ui/empty/empty-struct-tuple-pat.stderr
src/test/ui/error-codes/E0423.stderr
src/test/ui/feature-gates/feature-gate-macros_in_extern.rs [deleted file]
src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr [deleted file]
src/test/ui/issues/issue-19086.stderr
src/test/ui/issues/issue-32004.stderr
src/test/ui/issues/issue-63983.stderr
src/test/ui/lint/lint-unused-variables.rs
src/test/ui/lint/lint-unused-variables.stderr
src/test/ui/macros/issue-54441.rs
src/test/ui/macros/issue-54441.stderr
src/test/ui/macros/macro-first-set.rs
src/test/ui/macros/macro-meta-items-modern.rs [new file with mode: 0644]
src/test/ui/macros/macros-in-extern-rpass.rs [deleted file]
src/test/ui/macros/macros-in-extern.rs [new file with mode: 0644]
src/test/ui/methods/method-path-in-pattern.rs
src/test/ui/methods/method-path-in-pattern.stderr
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs [new file with mode: 0644]
src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr [new file with mode: 0644]
src/test/ui/or-patterns/multiple-pattern-typo.stderr
src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
src/test/ui/or-patterns/remove-leading-vert.fixed
src/test/ui/or-patterns/remove-leading-vert.rs
src/test/ui/or-patterns/remove-leading-vert.stderr
src/test/ui/panic-runtime/libtest-unwinds.rs [deleted file]
src/test/ui/panic-runtime/libtest-unwinds.stderr [deleted file]
src/test/ui/parser/recover-from-bad-variant.stderr
src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs [deleted file]
src/test/ui/proc-macro/dollar-crate-issue-62325.rs
src/test/ui/proc-macro/lifetimes.rs
src/test/ui/proc-macro/lifetimes.stderr
src/test/ui/proc-macro/macros-in-extern-derive.rs [new file with mode: 0644]
src/test/ui/proc-macro/macros-in-extern-derive.stderr [new file with mode: 0644]
src/test/ui/proc-macro/macros-in-extern-rpass.rs [deleted file]
src/test/ui/proc-macro/macros-in-extern.rs [new file with mode: 0644]
src/test/ui/proc-macro/macros-in-type.rs [new file with mode: 0644]
src/test/ui/proc-macro/proc-macro-gates.rs
src/test/ui/proc-macro/proc-macro-gates.stderr
src/test/ui/qualified/qualified-path-params.stderr
src/test/ui/resolve/issue-18252.stderr
src/test/ui/resolve/issue-19452.stderr
src/test/ui/resolve/issue-39226.stderr
src/test/ui/resolve/issue-6702.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/resolve/privacy-struct-ctor.stderr
src/test/ui/rfc-2565-param-attrs/attr-without-param.rs [new file with mode: 0644]
src/test/ui/rfc-2565-param-attrs/attr-without-param.stderr [new file with mode: 0644]
src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs
src/test/ui/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs [new file with mode: 0644]
src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.rs
src/test/ui/rfc-2565-param-attrs/param-attrs-builtin-attrs.stderr
src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.rs
src/test/ui/rfc-2565-param-attrs/param-attrs-cfg.stderr
src/test/ui/rfc-2565-param-attrs/param-attrs-pretty.rs
src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.rs
src/test/ui/rfc-2565-param-attrs/proc-macro-cannot-be-used.stderr
src/test/ui/span/E0493.stderr
src/test/ui/static/static-drop-scope.stderr
src/test/ui/struct-literal-variant-in-if.stderr
src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
src/test/ui/suggestions/issue-61226.stderr
src/test/ui/suggestions/match-needing-semi.fixed [new file with mode: 0644]
src/test/ui/suggestions/match-needing-semi.rs [new file with mode: 0644]
src/test/ui/suggestions/match-needing-semi.stderr [new file with mode: 0644]
src/test/ui/test-panic-abort-disabled.rs [new file with mode: 0644]
src/test/ui/test-panic-abort-disabled.stderr [new file with mode: 0644]
src/test/ui/test-panic-abort.rs [new file with mode: 0644]
src/test/ui/test-panic-abort.run.stdout [new file with mode: 0644]
src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-Self-issue-58006.stderr
src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/runtest.rs
src/tools/miri

index 5a92011d57033377abb7e80c56bc0b2016bee662..cbedb552a068e09b9cdaadb2953c7fe7bb3e4366 100644 (file)
@@ -566,7 +566,6 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "tempfile",
- "tester",
  "winapi 0.3.6",
 ]
 
@@ -3082,6 +3081,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fs_util",
+ "rustc_index",
  "rustc_macros",
  "rustc_target",
  "scoped-tls",
@@ -3362,6 +3362,7 @@ dependencies = [
  "rustc_errors",
  "rustc_fs_util",
  "rustc_incremental",
+ "rustc_index",
  "rustc_target",
  "serialize",
  "syntax",
@@ -3400,6 +3401,7 @@ dependencies = [
  "rustc-hash",
  "rustc-rayon",
  "rustc-rayon-core",
+ "rustc_index",
  "serialize",
  "smallvec",
  "stable_deref_trait",
@@ -3463,6 +3465,14 @@ dependencies = [
  "syntax_pos",
 ]
 
+[[package]]
+name = "rustc_index"
+version = "0.0.0"
+dependencies = [
+ "serialize",
+ "smallvec",
+]
+
 [[package]]
 name = "rustc_interface"
 version = "0.0.0"
@@ -3507,6 +3517,7 @@ dependencies = [
  "log",
  "rustc",
  "rustc_data_structures",
+ "rustc_index",
  "rustc_target",
  "syntax",
  "syntax_pos",
@@ -3552,6 +3563,7 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_index",
  "rustc_target",
  "serialize",
  "smallvec",
@@ -3574,6 +3586,7 @@ dependencies = [
  "rustc_apfloat",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_index",
  "rustc_lexer",
  "rustc_target",
  "serialize",
@@ -3673,6 +3686,7 @@ dependencies = [
  "bitflags",
  "log",
  "rustc_data_structures",
+ "rustc_index",
  "serialize",
  "syntax_pos",
 ]
@@ -3721,6 +3735,7 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_index",
  "rustc_target",
  "smallvec",
  "syntax",
@@ -4237,6 +4252,7 @@ dependencies = [
  "log",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_index",
  "rustc_lexer",
  "rustc_target",
  "scoped-tls",
@@ -4266,6 +4282,7 @@ dependencies = [
  "arena",
  "cfg-if",
  "rustc_data_structures",
+ "rustc_index",
  "rustc_macros",
  "scoped-tls",
  "serialize",
@@ -4323,16 +4340,6 @@ dependencies = [
  "std",
 ]
 
-[[package]]
-name = "term"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
-dependencies = [
- "kernel32-sys",
- "winapi 0.2.8",
-]
-
 [[package]]
 name = "term"
 version = "0.6.0"
@@ -4389,17 +4396,6 @@ dependencies = [
  "term 0.0.0",
 ]
 
-[[package]]
-name = "tester"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6"
-dependencies = [
- "getopts",
- "libc",
- "term 0.4.6",
-]
-
 [[package]]
 name = "textwrap"
 version = "0.11.0"
index 495ee46a9acb31abefff6855544b8b1d5e8a41bc..9462b10494c93e160d64fdfe1dfca11d06950b2f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ or reading the [rustc guide][rustcguidebuild].
    * `curl`
    * `git`
    * `ssl` which comes in `libssl-dev` or `openssl-devel`
-   * `pkg-config` if you are on compiling on Linux and targeting Linux
+   * `pkg-config` if you are compiling on Linux and targeting Linux
 
 2. Clone the [source] with `git`:
 
index fb8b63d7920b13fa488092b74517ca855f927bc8..8200bbe2fdce5d84576795f2ecde89322ca5849e 100755 (executable)
@@ -3,9 +3,11 @@
 set -ex
 source shared.sh
 
-VERSION=7.51.0
+VERSION=7.66.0
 
-curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf -
+curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \
+  | xz --decompress \
+  | tar xf -
 
 mkdir curl-build
 cd curl-build
index 29a22aa0315b048199497108d04b2bb1eac04e46..98d013dfa2b57616889bb8b3150111077fe90fcf 100644 (file)
@@ -1281,3 +1281,51 @@ fn test_stable_push_pop() {
     v.pop().unwrap();
     assert_eq!(*v0, 13);
 }
+
+// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on:
+//
+// ```
+// unsafe impl<T: ?Sized> IsZero for *mut T {
+//     fn is_zero(&self) -> bool {
+//         (*self).is_null()
+//     }
+// }
+// ```
+//
+// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`,
+// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component.
+// That is, a fat pointer can be “null” without being made entirely of zero bits.
+#[test]
+fn vec_macro_repeating_null_raw_fat_pointer() {
+    let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn();
+    let vtable = dbg!(ptr_metadata(raw_dyn));
+    let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable);
+    assert!(null_raw_dyn.is_null());
+
+    let vec = vec![null_raw_dyn; 1];
+    dbg!(ptr_metadata(vec[0]));
+    assert!(vec[0] == null_raw_dyn);
+
+    // Polyfill for https://github.com/rust-lang/rfcs/pull/2580
+
+    fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () {
+        unsafe {
+            std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable
+        }
+    }
+
+    fn ptr_from_raw_parts(data: *mut (), vtable: *mut()) -> *mut dyn Fn() {
+        unsafe {
+            std::mem::transmute::<DynRepr, *mut dyn Fn()>(DynRepr {
+                data,
+                vtable
+            })
+        }
+    }
+
+    #[repr(C)]
+    struct DynRepr {
+        data: *mut (),
+        vtable: *mut (),
+    }
+}
index e5672f8542ff65de2e781f399d77cbd5a18f7068..7c6ded08bbae9964fb44ce672775826b1fc9c72d 100644 (file)
@@ -1734,20 +1734,45 @@ fn is_zero(&self) -> bool {
 impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
 impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
 
-unsafe impl<T: ?Sized> IsZero for *const T {
+unsafe impl<T> IsZero for *const T {
     #[inline]
     fn is_zero(&self) -> bool {
         (*self).is_null()
     }
 }
 
-unsafe impl<T: ?Sized> IsZero for *mut T {
+unsafe impl<T> IsZero for *mut T {
     #[inline]
     fn is_zero(&self) -> bool {
         (*self).is_null()
     }
 }
 
+// `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
+// For fat pointers, the bytes that would be the pointer metadata in the `Some` variant
+// are padding in the `None` variant, so ignoring them and zero-initializing instead is ok.
+
+unsafe impl<T: ?Sized> IsZero for Option<&T> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
+
+unsafe impl<T: ?Sized> IsZero for Option<&mut T> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
+
+unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.is_none()
+    }
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // Common trait implementations for Vec
index 8767625d4ed373e0783fe492dc51c1beef5449a0..95ad4272cedd0568a953edb9d0434cc6490a47dd 100644 (file)
@@ -368,15 +368,17 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
 /// make a difference in release builds (where a loop that has no side-effects
 /// is easily detected and eliminated), but is often a big win for debug builds.
 ///
-/// Note that `ptr::drop_in_place` already performs this check, so if your workload
-/// can be reduced to some small number of drop_in_place calls, using this is
-/// unnecessary. In particular note that you can drop_in_place a slice, and that
+/// Note that [`drop_in_place`] already performs this check, so if your workload
+/// can be reduced to some small number of [`drop_in_place`] calls, using this is
+/// unnecessary. In particular note that you can [`drop_in_place`] a slice, and that
 /// will do a single needs_drop check for all the values.
 ///
 /// Types like Vec therefore just `drop_in_place(&mut self[..])` without using
-/// needs_drop explicitly. Types like `HashMap`, on the other hand, have to drop
+/// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop
 /// values one at a time and should use this API.
 ///
+/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html
+/// [`HashMap`]: ../../std/collections/struct.HashMap.html
 ///
 /// # Examples
 ///
index 5569d99f8d81ddfe310210ac76b89dfe1bbd9c68..301e432c98dfc4a3af707cf9e2e87475090803c2 100644 (file)
@@ -46,7 +46,7 @@
 //! # Options and pointers ("nullable" pointers)
 //!
 //! Rust's pointer types must always point to a valid location; there are
-//! no "null" pointers. Instead, Rust has *optional* pointers, like
+//! no "null" references. Instead, Rust has *optional* pointers, like
 //! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
 //!
 //! The following example uses [`Option`] to create an optional box of
index 5ec21e6d9286266d4ceb5561367ac3ef01ec1890..b5462d988378be5c6f099456ffae8ccfa44d7036 100644 (file)
@@ -28,7 +28,7 @@
 use crate::intrinsics::{assume, exact_div, unchecked_sub, is_aligned_and_not_null};
 use crate::isize;
 use crate::iter::*;
-use crate::ops::{FnMut, Try, self};
+use crate::ops::{FnMut, self};
 use crate::option::Option;
 use crate::option::Option::{None, Some};
 use crate::result::Result;
@@ -3180,39 +3180,6 @@ fn last(mut self) -> Option<$elem> {
                 self.next_back()
             }
 
-            #[inline]
-            fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
-                Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
-            {
-                // manual unrolling is needed when there are conditional exits from the loop
-                let mut accum = init;
-                unsafe {
-                    while len!(self) >= 4 {
-                        accum = f(accum, next_unchecked!(self))?;
-                        accum = f(accum, next_unchecked!(self))?;
-                        accum = f(accum, next_unchecked!(self))?;
-                        accum = f(accum, next_unchecked!(self))?;
-                    }
-                    while !is_empty!(self) {
-                        accum = f(accum, next_unchecked!(self))?;
-                    }
-                }
-                Try::from_ok(accum)
-            }
-
-            #[inline]
-            fn fold<Acc, Fold>(mut self, init: Acc, mut f: Fold) -> Acc
-                where Fold: FnMut(Acc, Self::Item) -> Acc,
-            {
-                // Let LLVM unroll this, rather than using the default
-                // impl that would force the manual unrolling above
-                let mut accum = init;
-                while let Some(x) = self.next() {
-                    accum = f(accum, x);
-                }
-                accum
-            }
-
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
@@ -3283,40 +3250,6 @@ fn nth_back(&mut self, n: usize) -> Option<$elem> {
                     Some(next_back_unchecked!(self))
                 }
             }
-
-            #[inline]
-            fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
-                Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
-            {
-                // manual unrolling is needed when there are conditional exits from the loop
-                let mut accum = init;
-                unsafe {
-                    while len!(self) >= 4 {
-                        accum = f(accum, next_back_unchecked!(self))?;
-                        accum = f(accum, next_back_unchecked!(self))?;
-                        accum = f(accum, next_back_unchecked!(self))?;
-                        accum = f(accum, next_back_unchecked!(self))?;
-                    }
-                    // inlining is_empty everywhere makes a huge performance difference
-                    while !is_empty!(self) {
-                        accum = f(accum, next_back_unchecked!(self))?;
-                    }
-                }
-                Try::from_ok(accum)
-            }
-
-            #[inline]
-            fn rfold<Acc, Fold>(mut self, init: Acc, mut f: Fold) -> Acc
-                where Fold: FnMut(Acc, Self::Item) -> Acc,
-            {
-                // Let LLVM unroll this, rather than using the default
-                // impl that would force the manual unrolling above
-                let mut accum = init;
-                while let Some(x) = self.next_back() {
-                    accum = f(accum, x);
-                }
-                accum
-            }
         }
 
         #[stable(feature = "fused", since = "1.26.0")]
index 0834faf1324245b9249c0625b5a56a14e6e95fc4..a7c94d057dc49624ca3119a9daec9056239b7c06 100644 (file)
@@ -25,6 +25,7 @@ rustc_apfloat = { path = "../librustc_apfloat" }
 rustc_target = { path = "../librustc_target" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_index = { path = "../librustc_index" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
index 5d06f62f4461673bd8ceed99a219d51cf4d32ec3..5a5919d786638d3dcbf87444d95fa76de6afe473 100644 (file)
@@ -26,12 +26,12 @@ macro_rules! arena_types {
             [] steal_mir: rustc::ty::steal::Steal<rustc::mir::Body<$tcx>>,
             [] mir: rustc::mir::Body<$tcx>,
             [] steal_promoted: rustc::ty::steal::Steal<
-                rustc_data_structures::indexed_vec::IndexVec<
+                rustc_index::vec::IndexVec<
                     rustc::mir::Promoted,
                     rustc::mir::Body<$tcx>
                 >
             >,
-            [] promoted: rustc_data_structures::indexed_vec::IndexVec<
+            [] promoted: rustc_index::vec::IndexVec<
                 rustc::mir::Promoted,
                 rustc::mir::Body<$tcx>
             >,
@@ -45,7 +45,7 @@ macro_rules! arena_types {
             [decode] specialization_graph: rustc::traits::specialization_graph::Graph,
             [] region_scope_tree: rustc::middle::region::ScopeTree,
             [] item_local_set: rustc::util::nodemap::ItemLocalSet,
-            [decode] mir_const_qualif: rustc_data_structures::bit_set::BitSet<rustc::mir::Local>,
+            [decode] mir_const_qualif: rustc_index::bit_set::BitSet<rustc::mir::Local>,
             [] trait_impls_of: rustc::ty::trait_def::TraitImpls,
             [] dropck_outlives:
                 rustc::infer::canonical::Canonical<'tcx,
index acfdc91523f70fce25036ac59148d453d304e0b4..0c56fc7914b4cfe505a153a9c8782071c378474b 100644 (file)
@@ -1,7 +1,7 @@
 use errors::Diagnostic;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use smallvec::SmallVec;
 use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering};
 use std::env;
@@ -26,7 +26,7 @@ pub struct DepGraph {
     data: Option<Lrc<DepGraphData>>,
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct DepNodeIndex { .. }
 }
 
index b64f71ed908d823b079ced68670c3ae55389755a..4302195755ea5ef5cce99f653990e2fd3fa30943 100644 (file)
@@ -2,9 +2,9 @@
 
 use crate::dep_graph::DepNode;
 use crate::ich::Fingerprint;
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct SerializedDepNodeIndex { .. }
 }
 
index d0bdc149131835c8bc62d9c300d18e37c1c2669d..13200b38f2cdae131c80ef933f7026748956d6cc 100644 (file)
@@ -1,9 +1,9 @@
 use crate::ty::{self, TyCtxt};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use std::fmt;
 use std::u32;
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct CrateId {
         ENCODABLE = custom
     }
@@ -87,7 +87,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl rustc_serialize::UseSpecializedEncodable for CrateNum {}
 impl rustc_serialize::UseSpecializedDecodable for CrateNum {}
 
-newtype_index! {
+rustc_index::newtype_index! {
     /// A DefIndex is an index into the hir-map for a crate, identifying a
     /// particular definition. It should really be considered an interned
     /// shorthand for a particular DefPath.
index 6f51e05881be5ef7e7236cd989a211c4877dab42..2238a56b29d04b150139935aed91f6deaa676067 100644 (file)
@@ -52,7 +52,7 @@
 use crate::util::nodemap::{DefIdMap, NodeMap};
 use errors::Applicability;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_data_structures::sync::Lrc;
 
@@ -988,10 +988,12 @@ fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
         // lower attributes (we use the AST version) there is nowhere to keep
         // the `HirId`s. We don't actually need HIR version of attributes anyway.
         Attribute {
+            item: AttrItem {
+                path: attr.path.clone(),
+                tokens: self.lower_token_stream(attr.tokens.clone()),
+            },
             id: attr.id,
             style: attr.style,
-            path: attr.path.clone(),
-            tokens: self.lower_token_stream(attr.tokens.clone()),
             is_sugared_doc: attr.is_sugared_doc,
             span: attr.span,
         }
index 2f0a318d5363e5adfb72de176d2b7b3e23a33d90..9dcecedd97caef4a0e102d31e90a994a99e6a2e2 100644 (file)
@@ -1037,10 +1037,9 @@ fn lower_expr_for(
     ) -> hir::Expr {
         // expand <head>
         let mut head = self.lower_expr(head);
-        let head_sp = head.span;
         let desugared_span = self.mark_span_with_reason(
             DesugaringKind::ForLoop,
-            head_sp,
+            head.span,
             None,
         );
         head.span = desugared_span;
@@ -1086,21 +1085,21 @@ fn lower_expr_for(
 
         // `match ::std::iter::Iterator::next(&mut iter) { ... }`
         let match_expr = {
-            let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
-            let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
+            let iter = P(self.expr_ident(desugared_span, iter, iter_pat_nid));
+            let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
             let next_path = &[sym::iter, sym::Iterator, sym::next];
             let next_expr = P(self.expr_call_std_path(
-                head_sp,
+                desugared_span,
                 next_path,
                 hir_vec![ref_mut_iter],
             ));
             let arms = hir_vec![pat_arm, break_arm];
 
-            self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
+            self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
         };
-        let match_stmt = self.stmt_expr(head_sp, match_expr);
+        let match_stmt = self.stmt_expr(desugared_span, match_expr);
 
-        let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
+        let next_expr = P(self.expr_ident(desugared_span, next_ident, next_pat_hid));
 
         // `let mut __next`
         let next_let = self.stmt_let_pat(
@@ -1115,7 +1114,7 @@ fn lower_expr_for(
         let pat = self.lower_pat(pat);
         let pat_let = self.stmt_let_pat(
             ThinVec::new(),
-            head_sp,
+            desugared_span,
             Some(next_expr),
             pat,
             hir::LocalSource::ForLoopDesugar,
@@ -1152,14 +1151,14 @@ fn lower_expr_for(
             let into_iter_path =
                 &[sym::iter, sym::IntoIterator, sym::into_iter];
             P(self.expr_call_std_path(
-                head_sp,
+                desugared_span,
                 into_iter_path,
                 hir_vec![head],
             ))
         };
 
         let match_expr = P(self.expr_match(
-            head_sp,
+            desugared_span,
             into_iter_expr,
             hir_vec![iter_arm],
             hir::MatchSource::ForLoopDesugar,
@@ -1171,7 +1170,7 @@ fn lower_expr_for(
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
+        self.expr_drop_temps(desugared_span, match_expr, e.attrs.clone())
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
index 540d456daf3d39b5879669674a08c202e97e6c08..1a970c7a2c1e04c9659c736f9ea8b945b79584ae 100644 (file)
@@ -5,7 +5,7 @@
 use crate::hir::def_id::{LOCAL_CRATE, CrateNum};
 use crate::hir::intravisit::{Visitor, NestedVisitorMap};
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use crate::ich::Fingerprint;
 use crate::middle::cstore::CrateStore;
 use crate::session::CrateDisambiguator;
index 187bc5933246078819b9cba87d3a819c453c9677..71bf230e37dedd8539e1d6dd2b665c1dec28d7fd 100644 (file)
@@ -11,7 +11,7 @@
 use crate::util::nodemap::NodeMap;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::{IndexVec};
+use rustc_index::vec::{IndexVec};
 use rustc_data_structures::stable_hasher::StableHasher;
 use std::borrow::Borrow;
 use std::fmt::Write;
index 42a4a9909f8a94e0c433aa8a7c9b3b284360ee13..1705f5692d4f9698c176921f45813021c0deaf67 100644 (file)
@@ -17,7 +17,7 @@
 
 use rustc_target::spec::abi::Abi;
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use syntax::ast::{self, Name, NodeId};
 use syntax::source_map::Spanned;
 use syntax::ext::base::MacroKind;
@@ -818,6 +818,32 @@ pub fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
         CRATE_HIR_ID
     }
 
+    /// When on a match arm tail expression or on a match arm, give back the enclosing `match`
+    /// expression.
+    ///
+    /// Used by error reporting when there's a type error in a match arm caused by the `match`
+    /// expression needing to be unit.
+    pub fn get_match_if_cause(&self, hir_id: HirId) -> Option<&Expr> {
+        for (_, node) in ParentHirIterator::new(hir_id, &self) {
+            match node {
+                Node::Item(_) |
+                Node::ForeignItem(_) |
+                Node::TraitItem(_) |
+                Node::ImplItem(_) => break,
+                Node::Expr(expr) => match expr.kind {
+                    ExprKind::Match(_, _, _) => return Some(expr),
+                    _ => {}
+                },
+                Node::Stmt(stmt) => match stmt.kind {
+                    StmtKind::Local(_) => break,
+                    _ => {}
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+
     /// Returns the nearest enclosing scope. A scope is roughly an item or block.
     pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
         for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
index 4e8b4337cc6dd0d3f23179f9eab612410fbf98cc..9ae661f0952a479990ed68ca2cd3cf6038325324 100644 (file)
@@ -122,9 +122,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 // Hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module.
 mod item_local_id_inner {
-    use rustc_data_structures::indexed_vec::Idx;
+    use rustc_index::vec::Idx;
     use rustc_macros::HashStable;
-    newtype_index! {
+    rustc_index::newtype_index! {
         /// An `ItemLocalId` uniquely identifies something within a given "item-like";
         /// that is, within a `hir::Item`, `hir::TraitItem`, or `hir::ImplItem`. There is no
         /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
index bdcf9e42ac2a88ae5cbeecb77537af5bed3f7fc4..23a2f115e05e2516fbb0acc8a38106c89812c0ac 100644 (file)
@@ -196,6 +196,11 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
     }
 }
 
+impl_stable_hash_for!(struct ::syntax::ast::AttrItem {
+    path,
+    tokens,
+});
+
 impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         // Make sure that these have been filtered out.
@@ -203,19 +208,15 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
         debug_assert!(!self.is_sugared_doc);
 
         let ast::Attribute {
+            ref item,
             id: _,
             style,
-            ref path,
-            ref tokens,
             is_sugared_doc: _,
             span,
         } = *self;
 
+        item.hash_stable(hcx, hasher);
         style.hash_stable(hcx, hasher);
-        path.hash_stable(hcx, hasher);
-        for tt in tokens.trees() {
-            tt.hash_stable(hcx, hasher);
-        }
         span.hash_stable(hcx, hasher);
     }
 }
index 2ea1317a94fd952ddbae9b1e1a98fbdaaf40e055..b9474f869ee29a6fee355ef43ca0896e5dd9e12c 100644 (file)
@@ -18,7 +18,7 @@
 use crate::ty::flags::FlagComputation;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use smallvec::SmallVec;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
index 4e442608f0e7e3211f76abe5a9f01d29af3308ad..562a463ded86ae831f605a971cb68bfd5b6c01d6 100644 (file)
@@ -25,7 +25,7 @@
 use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind};
 use crate::infer::region_constraints::MemberConstraint;
 use crate::mir::interpret::ConstValue;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_serialize::UseSpecializedDecodable;
 use smallvec::SmallVec;
index 18c1b41d5bb4c785ed86163e76abd283c4665c34..95b6a8bc84342c897b2278251ca3a5a08f4943a8 100644 (file)
@@ -17,8 +17,8 @@
 use crate::infer::InferCtxtBuilder;
 use crate::infer::{InferCtxt, InferOk, InferResult};
 use crate::mir::interpret::ConstValue;
-use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::Idx;
+use rustc_index::vec::IndexVec;
 use std::fmt::Debug;
 use syntax_pos::DUMMY_SP;
 use crate::traits::query::{Fallible, NoSolution};
index 6282fde59cad4dadfcbe3856a1e5d84933fe9011..f11f94c428e86a54ef2ffe667a56166648ebffbd 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
 };
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use smallvec::SmallVec;
 use std::fmt;
 use syntax_pos::Span;
index 21904edb309cb4b2efe6de2899465f6c9c9ec843..b4b4d1fe3e1f6bb56d101ec20a8feb9bde00c2fe 100644 (file)
@@ -7,7 +7,7 @@
 use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unify as ut;
 use crate::hir::def_id::DefId;
index c1435551a591854918a745eb7bad2ab337566da5..7b5aea8ac9847cd6dfef58ada70f14631272cf2a 100644 (file)
@@ -5,7 +5,7 @@
 use crate::ty::query::Providers;
 
 use rustc_target::spec::abi::Abi::RustIntrinsic;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use syntax_pos::{Span, sym};
 use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use crate::hir;
index 05e4d11c3f99004432beed9521899c3f28a843fe..9ff205228a566375bdeb17d20b5610bc69c04d5b 100644 (file)
@@ -16,8 +16,8 @@
 use crate::ty::{self, DefIdTree, TyCtxt};
 use crate::ty::query::Providers;
 
-use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
 use syntax::source_map;
 use syntax_pos::{Span, DUMMY_SP};
@@ -131,7 +131,7 @@ pub enum ScopeData {
     Remainder(FirstStatementIndex)
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     /// Represents a subscope of `block` for a binding that is introduced
     /// by `block.stmts[first_statement_index]`. Such subscopes represent
     /// a suffix of the block. Note that each subscope does not include
index d8d3383903d4b5c93843e0db724984ffab573548..9b4136674187660019feec9c1a7af61459f5fcc6 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::sync::{RwLock, MappedReadGuard, ReadGuard};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
index cd58396d95c62b6dcdea6607a6eb653a709e3093..e925d7429fff446f269d00b145b082a09aef63c3 100644 (file)
@@ -101,7 +101,7 @@ macro_rules! throw_exhaust {
     InvalidProgramInfo, ResourceExhaustionInfo, UndefinedBehaviorInfo,
 };
 
-pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue};
+pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue, get_slice_bytes};
 
 pub use self::allocation::{Allocation, AllocationExtra, Relocations, UndefMask};
 
index b8bc74141973882f992c236832f625986dfc7945..32f45cd9d472035ab601b8abc78a4b85396acbdd 100644 (file)
@@ -611,3 +611,18 @@ pub fn to_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
     Scalar(v),
     Undef
 });
+
+/// Gets the bytes of a constant slice value.
+pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] {
+    if let ConstValue::Slice { data, start, end } = val {
+        let len = end - start;
+        data.get_bytes(
+            cx,
+            // invent a pointer, only the offset is relevant anyway
+            Pointer::new(AllocId(0), Size::from_bytes(start as u64)),
+            Size::from_bytes(len as u64),
+        ).unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
+    } else {
+        bug!("expected const slice, but found another const value");
+    }
+}
index 5e12c4dfe75a53f0da7022d8ba85a9d20acc3671..6664e16895ae60b2e55c0016a4e8386cca04c909 100644 (file)
 };
 
 use polonius_engine::Atom;
-use rustc_data_structures::bit_set::BitMatrix;
+use rustc_index::bit_set::BitMatrix;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::{dominators, Dominators};
 use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::sync::MappedReadGuard;
 use rustc_macros::HashStable;
@@ -581,7 +581,7 @@ pub fn allows_two_phase_borrow(&self) -> bool {
 ///////////////////////////////////////////////////////////////////////////
 // Variables and temps
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct Local {
         derive [HashStable]
         DEBUG_FORMAT = "_{}",
@@ -994,7 +994,7 @@ pub struct UpvarDebuginfo {
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlock
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct BasicBlock {
         derive [HashStable]
         DEBUG_FORMAT = "bb{}",
@@ -1832,7 +1832,7 @@ fn is_indirect(&self) -> bool {
 /// need neither the `V` parameter for `Index` nor the `T` for `Field`.
 pub type ProjectionKind = ProjectionElem<(), ()>;
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct Field {
         derive [HashStable]
         DEBUG_FORMAT = "field[{}]"
@@ -2047,7 +2047,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 ///////////////////////////////////////////////////////////////////////////
 // Scopes
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct SourceScope {
         derive [HashStable]
         DEBUG_FORMAT = "scope[{}]",
@@ -2586,7 +2586,7 @@ fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct Promoted {
         derive [HashStable]
         DEBUG_FORMAT = "promoted[{}]"
@@ -2743,7 +2743,7 @@ pub struct UnsafetyCheckResult {
     pub unsafe_blocks: Lrc<[(hir::HirId, bool)]>,
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct GeneratorSavedLocal {
         derive [HashStable]
         DEBUG_FORMAT = "_{}",
index 1416a5f0a6e9ffc713d1f2e5b11b7aa01dd3cf45..f129dd3abeff7b1d6431fb82818b1a3aca0408ed 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 
 use super::*;
 
index 4b1558592aee3a7f0015a567254868aaaebe22e7..e463810b7af5fb279cf653564d6f982eab31c58d 100644 (file)
             cache_on_disk_if { key.is_local() }
             load_cached(tcx, id) {
                 let promoted: Option<
-                    rustc_data_structures::indexed_vec::IndexVec<
+                    rustc_index::vec::IndexVec<
                         crate::mir::Promoted,
                         crate::mir::Body<'tcx>
                     >> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id);
index 7c97fd11af2a534eb0b0d48cf3e8e6f185d3bbdb..50aa036f723a0f802b774142ceec6b3774832ae1 100644 (file)
@@ -1279,6 +1279,8 @@ fn parse_symbol_mangling_version(
         "show extended diagnostic help"),
     terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
         "set the current terminal width"),
+    panic_abort_tests: bool = (false, parse_bool, [TRACKED],
+        "support compiling tests with panic=abort"),
     continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
         "attempt to recover from parse errors (experimental)"),
     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
index e1ca9a16d965f690eb5df33c39b0d439659c1ed2..ef79417c6f084b96348ddfcd671d032991fc2225 100644 (file)
@@ -40,7 +40,7 @@
 use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
 use crate::hir;
-use rustc_data_structures::bit_set::GrowableBitSet;
+use rustc_index::bit_set::GrowableBitSet;
 use rustc_data_structures::sync::Lock;
 use rustc_target::spec::abi::Abi;
 use syntax::attr;
index 7626ecd424347e7787a8d1afee55fa95f4deb0e1..ffe1a11e81a11e7f31c8dd8029af1c4d7a8236a7 100644 (file)
@@ -52,7 +52,7 @@
 use rustc_data_structures::stable_hasher::{
     HashStable, StableHasher, StableVec, hash_stable_hashmap,
 };
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_data_structures::sharded::ShardedHashMap;
 use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal};
 use std::any::Any;
@@ -812,7 +812,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct UserTypeAnnotationIndex {
         derive [HashStable]
         DEBUG_FORMAT = "UserType({})",
index 6ab4f4c6112f779b23b2da2f8ab331aa48595a02..6b22ded49f3fc1ba3cad06a9dd473794c27edc97 100644 (file)
@@ -17,9 +17,9 @@
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::GeneratorSubsts;
 use crate::ty::subst::Subst;
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::bit_set::BitSet;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_index::vec::{IndexVec, Idx};
 
 pub use rustc_target::abi::*;
 use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi};
index 683c977499c6a41f36ea88a1776b924abfddbff8..4b9117f71be5ce0214fe1f965fed9a82f8a30057 100644 (file)
@@ -51,8 +51,8 @@
 
 use smallvec;
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
+use rustc_index::vec::{Idx, IndexVec};
 
 use crate::hir;
 
@@ -1536,7 +1536,7 @@ pub fn is_empty(&self) -> bool {
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     /// "Universes" are used during type- and trait-checking in the
     /// presence of `for<..>` binders to control what sets of names are
     /// visible. Universes are arranged into a tree: the root universe
index f559cde4b03cf90d59e027edc538a895d283d441..863721a5b4b79f7aff74b37f4aed52c7bffca43f 100644 (file)
 use crate::ty::util::NeedsDrop;
 use crate::ty::subst::SubstsRef;
 use crate::util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
-use crate::util::common::{ErrorReported};
+use crate::util::common::ErrorReported;
 use crate::util::profiling::ProfileCategory::*;
 
 use rustc_data_structures::svh::Svh;
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::fx::{FxIndexMap, FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::StableVec;
 use rustc_data_structures::sync::Lrc;
index c20e75868895991ac0871d418955a43f5c2204e6..97fafe341a3114ec5c82dc5f0cffce40741eb650 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once};
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 use rustc_serialize::{
     Decodable, Decoder, Encodable, Encoder, SpecializedDecoder, SpecializedEncoder,
     UseSpecializedDecodable, UseSpecializedEncodable, opaque,
index 2af6963f7122a9b8f8baed618826ae1f1ce25d16..3bd61e345543692978bb9ca03d6082d1063e30fd 100644 (file)
@@ -8,7 +8,7 @@
 use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use crate::ty::error::{ExpectedFound, TypeError};
-use crate::mir::interpret::{ConstValue, Scalar};
+use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar};
 use std::rc::Rc;
 use std::iter;
 use rustc_target::spec::abi;
@@ -584,7 +584,20 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         // FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment
         // saying that we're not handling it intentionally.
 
-        // FIXME(const_generics): handle `ConstValue::ByRef` and `ConstValue::Slice`.
+        (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => {
+            let a_bytes = get_slice_bytes(&tcx, a_val);
+            let b_bytes = get_slice_bytes(&tcx, b_val);
+            if a_bytes == b_bytes {
+                Ok(tcx.mk_const(ty::Const {
+                    val: a_val,
+                    ty: a.ty,
+                }))
+            } else {
+                Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+            }
+        }
+
+        // FIXME(const_generics): handle `ConstValue::ByRef`.
 
         // FIXME(const_generics): this is wrong, as it is a projection
         (ConstValue::Unevaluated(a_def_id, a_substs),
index 42d632d120ea1992a34f70261b22f62df6d698ad..6b0df7fb92a4a0c0a3779fab388f99ae1b665d5f 100644 (file)
@@ -9,7 +9,7 @@
 use crate::ty::{self, Lift, Ty, TyCtxt, InferConst};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::print::{FmtPrinter, Printer};
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 use smallvec::SmallVec;
 use crate::mir::interpret;
 
index 91479751ef41d3544f3ae85d719477e832fef5a5..e105c44d09ae5ef0ea8cdabc25c2a94a7d782646 100644 (file)
@@ -8,12 +8,12 @@
 use crate::mir::interpret::ConstValue;
 use crate::middle::region;
 use polonius_engine::Atom;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
 use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, GenericArg, GenericArgKind};
 use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable};
 use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
-use crate::ty::layout::VariantIdx;
+use crate::ty::layout::{Size, Integer, IntegerExt, VariantIdx};
 use crate::util::captures::Captures;
 use crate::mir::interpret::{Scalar, GlobalId};
 
@@ -24,6 +24,7 @@
 use std::ops::Range;
 use rustc_target::spec::abi;
 use syntax::ast::{self, Ident};
+use syntax::attr::{SignedInt, UnsignedInt};
 use syntax::symbol::{kw, InternedString};
 
 use self::InferTy::*;
@@ -1165,7 +1166,7 @@ pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     /// A [De Bruijn index][dbi] is a standard means of representing
     /// regions (and perhaps later types) in a higher-ranked setting. In
     /// particular, imagine a type like this:
@@ -1349,7 +1350,7 @@ pub struct FloatVid {
     pub index: u32,
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct RegionVid {
         DEBUG_FORMAT = custom,
     }
@@ -1376,7 +1377,7 @@ pub enum InferTy {
     FreshFloatTy(u32),
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct BoundVar { .. }
 }
 
@@ -2298,8 +2299,21 @@ pub fn try_eval_bits(
         ty: Ty<'tcx>,
     ) -> Option<u128> {
         assert_eq!(self.ty, ty);
+        // This is purely an optimization -- layout_of is a pretty expensive operation,
+        // but if we can determine the size without calling it, we don't need all that complexity
+        // (hashing, caching, etc.). As such, try to skip it.
+        let size = match ty.kind {
+            ty::Bool => Size::from_bytes(1),
+            ty::Char => Size::from_bytes(4),
+            ty::Int(ity) => {
+                Integer::from_attr(&tcx, SignedInt(ity)).size()
+            }
+            ty::Uint(uty) => {
+                Integer::from_attr(&tcx, UnsignedInt(uty)).size()
+            }
+            _ => tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size,
+        };
         // if `ty` does not depend on generic parameters, use an empty param_env
-        let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
         self.eval(tcx, param_env).val.try_to_bits(size)
     }
 
index 8b3ed5b0c623a5533bf9ec0047c8cda51b2617e8..bdb7467a1010c1b5e4c760f84f35cec3c6e906fc 100644 (file)
@@ -11,8 +11,8 @@
 
 use syntax_pos::Pos;
 
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::{Idx, IndexVec};
 
 use syntax_pos::BytePos;
 
index 4efa1993d432273476bffdee22109b491ac18acb..e0e0cd5f739e2718474d2b2828948cf8a2157901 100644 (file)
@@ -26,7 +26,7 @@
 use rustc::session::config::{self, DebugInfo};
 use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
 use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess,
     VariableKind, FunctionDebugContextData, type_names};
 
index 2a63011c2f54525ff433f10c36648347a088a82d..309a17a01e3fa375396d7c25ab88dbc447ba7fbf 100644 (file)
@@ -31,6 +31,7 @@
 #[macro_use] extern crate rustc;
 extern crate rustc_target;
 #[macro_use] extern crate rustc_data_structures;
+extern crate rustc_index;
 extern crate rustc_incremental;
 extern crate rustc_codegen_utils;
 extern crate rustc_codegen_ssa;
index 2e3666e6096573eda3bd08691807fdecf8f20c67..c7d09a423d5e3b7c2ec9aef13a13a4480c66c811 100644 (file)
@@ -29,4 +29,5 @@ rustc_data_structures = { path = "../librustc_data_structures"}
 rustc_errors = { path = "../librustc_errors" }
 rustc_fs_util = { path = "../librustc_fs_util" }
 rustc_incremental = { path = "../librustc_incremental" }
+rustc_index = { path = "../librustc_index" }
 rustc_target = { path = "../librustc_target" }
index d634b73430a583f2e7a0b46e86fe09a89ea5155f..9078f77f1f7a25db8580f9dc82e77b3b0d3e8172 100644 (file)
@@ -13,7 +13,7 @@
 use rustc::ty::query::Providers;
 use rustc::ty::subst::SubstsRef;
 use rustc::util::nodemap::{FxHashMap, DefIdMap};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use syntax::ext::allocator::ALLOCATOR_METHODS;
 
 pub type ExportedSymbols = FxHashMap<
index 90ed629bbc61e5fffb31d18e95d129fda036f782..d11d8911a93d592a3ce65d47c1687981290be516 100644 (file)
@@ -29,7 +29,7 @@
 use rustc::session::config::{self, EntryFnType, Lto};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc_codegen_utils::{symbol_names_test, check_for_rustc_errors_attr};
 use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
 use crate::mir::place::PlaceRef;
index 05896523863c25f55a6b316b4109a47cb2a50d27..ea1cf926fccf0a47ac537eeb371bcd48b4829f01 100644 (file)
@@ -1,9 +1,9 @@
 //! An analysis to determine which locals require allocas and
 //! which do not.
 
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc_data_structures::graph::dominators::Dominators;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use rustc::mir::{self, Location, TerminatorKind};
 use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
 use rustc::mir::traversal;
index 7ebdfbdcdeb2d6340980b1ce1198a1899f484dd4..3a1d0a2577521a09fc620690ecf5268d33e6c512 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc::middle::lang_items;
 use rustc::ty::{self, Ty, TypeFoldable, Instance};
 use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
index 9cfe410fcc5e036b532c047e20119da58a848587..d06359ab0ce89d4ffe694ae33538de89172368a5 100644 (file)
@@ -1,6 +1,6 @@
 use rustc::mir::interpret::ErrorHandled;
 use rustc::mir;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, HasTyCtxt};
 use syntax::source_map::Span;
index 4f3a8bdb540b5d853da642d0424d28e45b697e44..2a563e8290ed377c92d3bbab17654a6fbe44b62b 100644 (file)
@@ -13,8 +13,8 @@
 
 use std::iter;
 
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
 
 use self::analyze::CleanupKind;
 use self::place::PlaceRef;
index 9c16b864ef21dce3b48d1c017b16cb8b885848ac..e75f247da96135ed3a791f4359e7de62238474f3 100644 (file)
@@ -3,7 +3,7 @@
 use rustc::hir::def_id::CrateNum;
 use rustc::mir;
 use rustc::ty::{self, Ty, Instance};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use syntax::ast::Name;
 use syntax_pos::{SourceFile, Span};
 
index ae3403cf0ce9f6955b148f0fe10ede6d5300ecc2..e020f2f8da940e19d4a27c8b93e473eb77734702 100644 (file)
@@ -24,6 +24,7 @@ rayon = { version = "0.2.0", package = "rustc-rayon" }
 rayon-core = { version = "0.2.0", package = "rustc-rayon-core" }
 rustc-hash = "1.0.1"
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
+rustc_index = { path = "../librustc_index", package = "rustc_index" }
 
 [dependencies.parking_lot]
 version = "0.9"
diff --git a/src/librustc_data_structures/bit_set.rs b/src/librustc_data_structures/bit_set.rs
deleted file mode 100644 (file)
index fe8ef64..0000000
+++ /dev/null
@@ -1,984 +0,0 @@
-use crate::indexed_vec::{Idx, IndexVec};
-use smallvec::SmallVec;
-use std::fmt;
-use std::iter;
-use std::marker::PhantomData;
-use std::mem;
-use std::slice;
-
-#[cfg(test)]
-mod tests;
-
-pub type Word = u64;
-pub const WORD_BYTES: usize = mem::size_of::<Word>();
-pub const WORD_BITS: usize = WORD_BYTES * 8;
-
-/// A fixed-size bitset type with a dense representation. It does not support
-/// resizing after creation; use `GrowableBitSet` for that.
-///
-/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
-/// just be `usize`.
-///
-/// All operations that involve an element will panic if the element is equal
-/// to or greater than the domain size. All operations that involve two bitsets
-/// will panic if the bitsets have differing domain sizes.
-#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
-pub struct BitSet<T: Idx> {
-    domain_size: usize,
-    words: Vec<Word>,
-    marker: PhantomData<T>,
-}
-
-impl<T: Idx> BitSet<T> {
-    /// Creates a new, empty bitset with a given `domain_size`.
-    #[inline]
-    pub fn new_empty(domain_size: usize) -> BitSet<T> {
-        let num_words = num_words(domain_size);
-        BitSet {
-            domain_size,
-            words: vec![0; num_words],
-            marker: PhantomData,
-        }
-    }
-
-    /// Creates a new, filled bitset with a given `domain_size`.
-    #[inline]
-    pub fn new_filled(domain_size: usize) -> BitSet<T> {
-        let num_words = num_words(domain_size);
-        let mut result = BitSet {
-            domain_size,
-            words: vec![!0; num_words],
-            marker: PhantomData,
-        };
-        result.clear_excess_bits();
-        result
-    }
-
-    /// Gets the domain size.
-    pub fn domain_size(&self) -> usize {
-        self.domain_size
-    }
-
-    /// Clear all elements.
-    #[inline]
-    pub fn clear(&mut self) {
-        for word in &mut self.words {
-            *word = 0;
-        }
-    }
-
-    /// Clear excess bits in the final word.
-    fn clear_excess_bits(&mut self) {
-        let num_bits_in_final_word = self.domain_size % WORD_BITS;
-        if num_bits_in_final_word > 0 {
-            let mask = (1 << num_bits_in_final_word) - 1;
-            let final_word_idx = self.words.len() - 1;
-            self.words[final_word_idx] &= mask;
-        }
-    }
-
-    /// Efficiently overwrite `self` with `other`.
-    pub fn overwrite(&mut self, other: &BitSet<T>) {
-        assert!(self.domain_size == other.domain_size);
-        self.words.clone_from_slice(&other.words);
-    }
-
-    /// Count the number of set bits in the set.
-    pub fn count(&self) -> usize {
-        self.words.iter().map(|e| e.count_ones() as usize).sum()
-    }
-
-    /// Returns `true` if `self` contains `elem`.
-    #[inline]
-    pub fn contains(&self, elem: T) -> bool {
-        assert!(elem.index() < self.domain_size);
-        let (word_index, mask) = word_index_and_mask(elem);
-        (self.words[word_index] & mask) != 0
-    }
-
-    /// Is `self` is a (non-strict) superset of `other`?
-    #[inline]
-    pub fn superset(&self, other: &BitSet<T>) -> bool {
-        assert_eq!(self.domain_size, other.domain_size);
-        self.words.iter().zip(&other.words).all(|(a, b)| (a & b) == *b)
-    }
-
-    /// Is the set empty?
-    #[inline]
-    pub fn is_empty(&self) -> bool {
-        self.words.iter().all(|a| *a == 0)
-    }
-
-    /// Insert `elem`. Returns whether the set has changed.
-    #[inline]
-    pub fn insert(&mut self, elem: T) -> bool {
-        assert!(elem.index() < self.domain_size);
-        let (word_index, mask) = word_index_and_mask(elem);
-        let word_ref = &mut self.words[word_index];
-        let word = *word_ref;
-        let new_word = word | mask;
-        *word_ref = new_word;
-        new_word != word
-    }
-
-    /// Sets all bits to true.
-    pub fn insert_all(&mut self) {
-        for word in &mut self.words {
-            *word = !0;
-        }
-        self.clear_excess_bits();
-    }
-
-    /// Returns `true` if the set has changed.
-    #[inline]
-    pub fn remove(&mut self, elem: T) -> bool {
-        assert!(elem.index() < self.domain_size);
-        let (word_index, mask) = word_index_and_mask(elem);
-        let word_ref = &mut self.words[word_index];
-        let word = *word_ref;
-        let new_word = word & !mask;
-        *word_ref = new_word;
-        new_word != word
-    }
-
-    /// Sets `self = self | other` and returns `true` if `self` changed
-    /// (i.e., if new bits were added).
-    pub fn union(&mut self, other: &impl UnionIntoBitSet<T>) -> bool {
-        other.union_into(self)
-    }
-
-    /// Sets `self = self - other` and returns `true` if `self` changed.
-    /// (i.e., if any bits were removed).
-    pub fn subtract(&mut self, other: &impl SubtractFromBitSet<T>) -> bool {
-        other.subtract_from(self)
-    }
-
-    /// Sets `self = self & other` and return `true` if `self` changed.
-    /// (i.e., if any bits were removed).
-    pub fn intersect(&mut self, other: &BitSet<T>) -> bool {
-        assert_eq!(self.domain_size, other.domain_size);
-        bitwise(&mut self.words, &other.words, |a, b| { a & b })
-    }
-
-    /// Gets a slice of the underlying words.
-    pub fn words(&self) -> &[Word] {
-        &self.words
-    }
-
-    /// Iterates over the indices of set bits in a sorted order.
-    #[inline]
-    pub fn iter(&self) -> BitIter<'_, T> {
-        BitIter {
-            cur: None,
-            iter: self.words.iter().enumerate(),
-            marker: PhantomData,
-        }
-    }
-
-    /// Duplicates the set as a hybrid set.
-    pub fn to_hybrid(&self) -> HybridBitSet<T> {
-        // Note: we currently don't bother trying to make a Sparse set.
-        HybridBitSet::Dense(self.to_owned())
-    }
-
-    /// Set `self = self | other`. In contrast to `union` returns `true` if the set contains at
-    /// least one bit that is not in `other` (i.e. `other` is not a superset of `self`).
-    ///
-    /// This is an optimization for union of a hybrid bitset.
-    fn reverse_union_sparse(&mut self, sparse: &SparseBitSet<T>) -> bool {
-        assert!(sparse.domain_size == self.domain_size);
-        self.clear_excess_bits();
-
-        let mut not_already = false;
-        // Index of the current word not yet merged.
-        let mut current_index = 0;
-        // Mask of bits that came from the sparse set in the current word.
-        let mut new_bit_mask = 0;
-        for (word_index, mask) in sparse.iter().map(|x| word_index_and_mask(*x)) {
-            // Next bit is in a word not inspected yet.
-            if word_index > current_index {
-                self.words[current_index] |= new_bit_mask;
-                // Were there any bits in the old word that did not occur in the sparse set?
-                not_already |= (self.words[current_index] ^ new_bit_mask) != 0;
-                // Check all words we skipped for any set bit.
-                not_already |= self.words[current_index+1..word_index].iter().any(|&x| x != 0);
-                // Update next word.
-                current_index = word_index;
-                // Reset bit mask, no bits have been merged yet.
-                new_bit_mask = 0;
-            }
-            // Add bit and mark it as coming from the sparse set.
-            // self.words[word_index] |= mask;
-            new_bit_mask |= mask;
-        }
-        self.words[current_index] |= new_bit_mask;
-        // Any bits in the last inspected word that were not in the sparse set?
-        not_already |= (self.words[current_index] ^ new_bit_mask) != 0;
-        // Any bits in the tail? Note `clear_excess_bits` before.
-        not_already |= self.words[current_index+1..].iter().any(|&x| x != 0);
-
-        not_already
-    }
-}
-
-/// This is implemented by all the bitsets so that BitSet::union() can be
-/// passed any type of bitset.
-pub trait UnionIntoBitSet<T: Idx> {
-    // Performs `other = other | self`.
-    fn union_into(&self, other: &mut BitSet<T>) -> bool;
-}
-
-/// This is implemented by all the bitsets so that BitSet::subtract() can be
-/// passed any type of bitset.
-pub trait SubtractFromBitSet<T: Idx> {
-    // Performs `other = other - self`.
-    fn subtract_from(&self, other: &mut BitSet<T>) -> bool;
-}
-
-impl<T: Idx> UnionIntoBitSet<T> for BitSet<T> {
-    fn union_into(&self, other: &mut BitSet<T>) -> bool {
-        assert_eq!(self.domain_size, other.domain_size);
-        bitwise(&mut other.words, &self.words, |a, b| { a | b })
-    }
-}
-
-impl<T: Idx> SubtractFromBitSet<T> for BitSet<T> {
-    fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
-        assert_eq!(self.domain_size, other.domain_size);
-        bitwise(&mut other.words, &self.words, |a, b| { a & !b })
-    }
-}
-
-impl<T: Idx> fmt::Debug for BitSet<T> {
-    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
-        w.debug_list()
-         .entries(self.iter())
-         .finish()
-    }
-}
-
-impl<T: Idx> ToString for BitSet<T> {
-    fn to_string(&self) -> String {
-        let mut result = String::new();
-        let mut sep = '[';
-
-        // Note: this is a little endian printout of bytes.
-
-        // i tracks how many bits we have printed so far.
-        let mut i = 0;
-        for word in &self.words {
-            let mut word = *word;
-            for _ in 0..WORD_BYTES { // for each byte in `word`:
-                let remain = self.domain_size - i;
-                // If less than a byte remains, then mask just that many bits.
-                let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
-                assert!(mask <= 0xFF);
-                let byte = word & mask;
-
-                result.push_str(&format!("{}{:02x}", sep, byte));
-
-                if remain <= 8 { break; }
-                word >>= 8;
-                i += 8;
-                sep = '-';
-            }
-            sep = '|';
-        }
-        result.push(']');
-
-        result
-    }
-}
-
-pub struct BitIter<'a, T: Idx> {
-    cur: Option<(Word, usize)>,
-    iter: iter::Enumerate<slice::Iter<'a, Word>>,
-    marker: PhantomData<T>
-}
-
-impl<'a, T: Idx> Iterator for BitIter<'a, T> {
-    type Item = T;
-    fn next(&mut self) -> Option<T> {
-        loop {
-            if let Some((ref mut word, offset)) = self.cur {
-                let bit_pos = word.trailing_zeros() as usize;
-                if bit_pos != WORD_BITS {
-                    let bit = 1 << bit_pos;
-                    *word ^= bit;
-                    return Some(T::new(bit_pos + offset))
-                }
-            }
-
-            let (i, word) = self.iter.next()?;
-            self.cur = Some((*word, WORD_BITS * i));
-        }
-    }
-}
-
-#[inline]
-fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
-    where Op: Fn(Word, Word) -> Word
-{
-    assert_eq!(out_vec.len(), in_vec.len());
-    let mut changed = false;
-    for (out_elem, in_elem) in out_vec.iter_mut().zip(in_vec.iter()) {
-        let old_val = *out_elem;
-        let new_val = op(old_val, *in_elem);
-        *out_elem = new_val;
-        changed |= old_val != new_val;
-    }
-    changed
-}
-
-const SPARSE_MAX: usize = 8;
-
-/// A fixed-size bitset type with a sparse representation and a maximum of
-/// `SPARSE_MAX` elements. The elements are stored as a sorted `SmallVec` with
-/// no duplicates; although `SmallVec` can spill its elements to the heap, that
-/// never happens within this type because of the `SPARSE_MAX` limit.
-///
-/// This type is used by `HybridBitSet`; do not use directly.
-#[derive(Clone, Debug)]
-pub struct SparseBitSet<T: Idx> {
-    domain_size: usize,
-    elems: SmallVec<[T; SPARSE_MAX]>,
-}
-
-impl<T: Idx> SparseBitSet<T> {
-    fn new_empty(domain_size: usize) -> Self {
-        SparseBitSet {
-            domain_size,
-            elems: SmallVec::new()
-        }
-    }
-
-    fn len(&self) -> usize {
-        self.elems.len()
-    }
-
-    fn is_empty(&self) -> bool {
-        self.elems.len() == 0
-    }
-
-    fn contains(&self, elem: T) -> bool {
-        assert!(elem.index() < self.domain_size);
-        self.elems.contains(&elem)
-    }
-
-    fn insert(&mut self, elem: T) -> bool {
-        assert!(elem.index() < self.domain_size);
-        let changed = if let Some(i) = self.elems.iter().position(|&e| e >= elem) {
-            if self.elems[i] == elem {
-                // `elem` is already in the set.
-                false
-            } else {
-                // `elem` is smaller than one or more existing elements.
-                self.elems.insert(i, elem);
-                true
-            }
-        } else {
-            // `elem` is larger than all existing elements.
-            self.elems.push(elem);
-            true
-        };
-        assert!(self.len() <= SPARSE_MAX);
-        changed
-    }
-
-    fn remove(&mut self, elem: T) -> bool {
-        assert!(elem.index() < self.domain_size);
-        if let Some(i) = self.elems.iter().position(|&e| e == elem) {
-            self.elems.remove(i);
-            true
-        } else {
-            false
-        }
-    }
-
-    fn to_dense(&self) -> BitSet<T> {
-        let mut dense = BitSet::new_empty(self.domain_size);
-        for elem in self.elems.iter() {
-            dense.insert(*elem);
-        }
-        dense
-    }
-
-    fn iter(&self) -> slice::Iter<'_, T> {
-        self.elems.iter()
-    }
-}
-
-impl<T: Idx> UnionIntoBitSet<T> for SparseBitSet<T> {
-    fn union_into(&self, other: &mut BitSet<T>) -> bool {
-        assert_eq!(self.domain_size, other.domain_size);
-        let mut changed = false;
-        for elem in self.iter() {
-            changed |= other.insert(*elem);
-        }
-        changed
-    }
-}
-
-impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
-    fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
-        assert_eq!(self.domain_size, other.domain_size);
-        let mut changed = false;
-        for elem in self.iter() {
-            changed |= other.remove(*elem);
-        }
-        changed
-    }
-}
-
-/// A fixed-size bitset type with a hybrid representation: sparse when there
-/// are up to a `SPARSE_MAX` elements in the set, but dense when there are more
-/// than `SPARSE_MAX`.
-///
-/// This type is especially efficient for sets that typically have a small
-/// number of elements, but a large `domain_size`, and are cleared frequently.
-///
-/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
-/// just be `usize`.
-///
-/// All operations that involve an element will panic if the element is equal
-/// to or greater than the domain size. All operations that involve two bitsets
-/// will panic if the bitsets have differing domain sizes.
-#[derive(Clone, Debug)]
-pub enum HybridBitSet<T: Idx> {
-    Sparse(SparseBitSet<T>),
-    Dense(BitSet<T>),
-}
-
-impl<T: Idx> HybridBitSet<T> {
-    pub fn new_empty(domain_size: usize) -> Self {
-        HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size))
-    }
-
-    fn domain_size(&self) -> usize {
-        match self {
-            HybridBitSet::Sparse(sparse) => sparse.domain_size,
-            HybridBitSet::Dense(dense) => dense.domain_size,
-        }
-    }
-
-    pub fn clear(&mut self) {
-        let domain_size = self.domain_size();
-        *self = HybridBitSet::new_empty(domain_size);
-    }
-
-    pub fn contains(&self, elem: T) -> bool {
-        match self {
-            HybridBitSet::Sparse(sparse) => sparse.contains(elem),
-            HybridBitSet::Dense(dense) => dense.contains(elem),
-        }
-    }
-
-    pub fn superset(&self, other: &HybridBitSet<T>) -> bool {
-        match (self, other) {
-            (HybridBitSet::Dense(self_dense), HybridBitSet::Dense(other_dense)) => {
-                self_dense.superset(other_dense)
-            }
-            _ => {
-                assert!(self.domain_size() == other.domain_size());
-                other.iter().all(|elem| self.contains(elem))
-            }
-        }
-    }
-
-    pub fn is_empty(&self) -> bool {
-        match self {
-            HybridBitSet::Sparse(sparse) => sparse.is_empty(),
-            HybridBitSet::Dense(dense) => dense.is_empty(),
-        }
-    }
-
-    pub fn insert(&mut self, elem: T) -> bool {
-        // No need to check `elem` against `self.domain_size` here because all
-        // the match cases check it, one way or another.
-        match self {
-            HybridBitSet::Sparse(sparse) if sparse.len() < SPARSE_MAX => {
-                // The set is sparse and has space for `elem`.
-                sparse.insert(elem)
-            }
-            HybridBitSet::Sparse(sparse) if sparse.contains(elem) => {
-                // The set is sparse and does not have space for `elem`, but
-                // that doesn't matter because `elem` is already present.
-                false
-            }
-            HybridBitSet::Sparse(sparse) => {
-                // The set is sparse and full. Convert to a dense set.
-                let mut dense = sparse.to_dense();
-                let changed = dense.insert(elem);
-                assert!(changed);
-                *self = HybridBitSet::Dense(dense);
-                changed
-            }
-            HybridBitSet::Dense(dense) => dense.insert(elem),
-        }
-    }
-
-    pub fn insert_all(&mut self) {
-        let domain_size = self.domain_size();
-        match self {
-            HybridBitSet::Sparse(_) => {
-                *self = HybridBitSet::Dense(BitSet::new_filled(domain_size));
-            }
-            HybridBitSet::Dense(dense) => dense.insert_all(),
-        }
-    }
-
-    pub fn remove(&mut self, elem: T) -> bool {
-        // Note: we currently don't bother going from Dense back to Sparse.
-        match self {
-            HybridBitSet::Sparse(sparse) => sparse.remove(elem),
-            HybridBitSet::Dense(dense) => dense.remove(elem),
-        }
-    }
-
-    pub fn union(&mut self, other: &HybridBitSet<T>) -> bool {
-        match self {
-            HybridBitSet::Sparse(self_sparse) => {
-                match other {
-                    HybridBitSet::Sparse(other_sparse) => {
-                        // Both sets are sparse. Add the elements in
-                        // `other_sparse` to `self` one at a time. This
-                        // may or may not cause `self` to be densified.
-                        assert_eq!(self.domain_size(), other.domain_size());
-                        let mut changed = false;
-                        for elem in other_sparse.iter() {
-                            changed |= self.insert(*elem);
-                        }
-                        changed
-                    }
-                    HybridBitSet::Dense(other_dense) => {
-                        // `self` is sparse and `other` is dense. To
-                        // merge them, we have two available strategies:
-                        // * Densify `self` then merge other
-                        // * Clone other then integrate bits from `self`
-                        // The second strategy requires dedicated method
-                        // since the usual `union` returns the wrong
-                        // result. In the dedicated case the computation
-                        // is slightly faster if the bits of the sparse
-                        // bitset map to only few words of the dense
-                        // representation, i.e. indices are near each
-                        // other.
-                        //
-                        // Benchmarking seems to suggest that the second
-                        // option is worth it.
-                        let mut new_dense = other_dense.clone();
-                        let changed = new_dense.reverse_union_sparse(self_sparse);
-                        *self = HybridBitSet::Dense(new_dense);
-                        changed
-                    }
-                }
-            }
-
-            HybridBitSet::Dense(self_dense) => self_dense.union(other),
-        }
-    }
-
-    /// Converts to a dense set, consuming itself in the process.
-    pub fn to_dense(self) -> BitSet<T> {
-        match self {
-            HybridBitSet::Sparse(sparse) => sparse.to_dense(),
-            HybridBitSet::Dense(dense) => dense,
-        }
-    }
-
-    pub fn iter(&self) -> HybridIter<'_, T> {
-        match self {
-            HybridBitSet::Sparse(sparse) => HybridIter::Sparse(sparse.iter()),
-            HybridBitSet::Dense(dense) => HybridIter::Dense(dense.iter()),
-        }
-    }
-}
-
-impl<T: Idx> UnionIntoBitSet<T> for HybridBitSet<T> {
-    fn union_into(&self, other: &mut BitSet<T>) -> bool {
-        match self {
-            HybridBitSet::Sparse(sparse) => sparse.union_into(other),
-            HybridBitSet::Dense(dense) => dense.union_into(other),
-        }
-    }
-}
-
-impl<T: Idx> SubtractFromBitSet<T> for HybridBitSet<T> {
-    fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
-        match self {
-            HybridBitSet::Sparse(sparse) => sparse.subtract_from(other),
-            HybridBitSet::Dense(dense) => dense.subtract_from(other),
-        }
-    }
-}
-
-pub enum HybridIter<'a, T: Idx> {
-    Sparse(slice::Iter<'a, T>),
-    Dense(BitIter<'a, T>),
-}
-
-impl<'a, T: Idx> Iterator for HybridIter<'a, T> {
-    type Item = T;
-
-    fn next(&mut self) -> Option<T> {
-        match self {
-            HybridIter::Sparse(sparse) => sparse.next().map(|e| *e),
-            HybridIter::Dense(dense) => dense.next(),
-        }
-    }
-}
-
-/// A resizable bitset type with a dense representation.
-///
-/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
-/// just be `usize`.
-///
-/// All operations that involve an element will panic if the element is equal
-/// to or greater than the domain size.
-#[derive(Clone, Debug, PartialEq)]
-pub struct GrowableBitSet<T: Idx> {
-    bit_set: BitSet<T>,
-}
-
-impl<T: Idx> GrowableBitSet<T> {
-    /// Ensure that the set can hold at least `min_domain_size` elements.
-    pub fn ensure(&mut self, min_domain_size: usize) {
-        if self.bit_set.domain_size < min_domain_size {
-            self.bit_set.domain_size = min_domain_size;
-        }
-
-        let min_num_words = num_words(min_domain_size);
-        if self.bit_set.words.len() < min_num_words {
-            self.bit_set.words.resize(min_num_words, 0)
-        }
-    }
-
-    pub fn new_empty() -> GrowableBitSet<T> {
-        GrowableBitSet { bit_set: BitSet::new_empty(0) }
-    }
-
-    pub fn with_capacity(capacity: usize) -> GrowableBitSet<T> {
-        GrowableBitSet { bit_set: BitSet::new_empty(capacity) }
-    }
-
-    /// Returns `true` if the set has changed.
-    #[inline]
-    pub fn insert(&mut self, elem: T) -> bool {
-        self.ensure(elem.index() + 1);
-        self.bit_set.insert(elem)
-    }
-
-    #[inline]
-    pub fn contains(&self, elem: T) -> bool {
-        let (word_index, mask) = word_index_and_mask(elem);
-        if let Some(word) = self.bit_set.words.get(word_index) {
-            (word & mask) != 0
-        } else {
-            false
-        }
-    }
-}
-
-/// A fixed-size 2D bit matrix type with a dense representation.
-///
-/// `R` and `C` are index types used to identify rows and columns respectively;
-/// typically newtyped `usize` wrappers, but they can also just be `usize`.
-///
-/// All operations that involve a row and/or column index will panic if the
-/// index exceeds the relevant bound.
-#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)]
-pub struct BitMatrix<R: Idx, C: Idx> {
-    num_rows: usize,
-    num_columns: usize,
-    words: Vec<Word>,
-    marker: PhantomData<(R, C)>,
-}
-
-impl<R: Idx, C: Idx> BitMatrix<R, C> {
-    /// Creates a new `rows x columns` matrix, initially empty.
-    pub fn new(num_rows: usize, num_columns: usize) -> BitMatrix<R, C> {
-        // For every element, we need one bit for every other
-        // element. Round up to an even number of words.
-        let words_per_row = num_words(num_columns);
-        BitMatrix {
-            num_rows,
-            num_columns,
-            words: vec![0; num_rows * words_per_row],
-            marker: PhantomData,
-        }
-    }
-
-    /// Creates a new matrix, with `row` used as the value for every row.
-    pub fn from_row_n(row: &BitSet<C>, num_rows: usize) -> BitMatrix<R, C> {
-        let num_columns = row.domain_size();
-        let words_per_row = num_words(num_columns);
-        assert_eq!(words_per_row, row.words().len());
-        BitMatrix {
-            num_rows,
-            num_columns,
-            words: iter::repeat(row.words()).take(num_rows).flatten().cloned().collect(),
-            marker: PhantomData,
-        }
-    }
-
-    pub fn rows(&self) -> impl Iterator<Item = R> {
-        (0..self.num_rows).map(R::new)
-    }
-
-    /// The range of bits for a given row.
-    fn range(&self, row: R) -> (usize, usize) {
-        let words_per_row = num_words(self.num_columns);
-        let start = row.index() * words_per_row;
-        (start, start + words_per_row)
-    }
-
-    /// Sets the cell at `(row, column)` to true. Put another way, insert
-    /// `column` to the bitset for `row`.
-    ///
-    /// Returns `true` if this changed the matrix.
-    pub fn insert(&mut self, row: R, column: C) -> bool {
-        assert!(row.index() < self.num_rows && column.index() < self.num_columns);
-        let (start, _) = self.range(row);
-        let (word_index, mask) = word_index_and_mask(column);
-        let words = &mut self.words[..];
-        let word = words[start + word_index];
-        let new_word = word | mask;
-        words[start + word_index] = new_word;
-        word != new_word
-    }
-
-    /// Do the bits from `row` contain `column`? Put another way, is
-    /// the matrix cell at `(row, column)` true?  Put yet another way,
-    /// if the matrix represents (transitive) reachability, can
-    /// `row` reach `column`?
-    pub fn contains(&self, row: R, column: C) -> bool {
-        assert!(row.index() < self.num_rows && column.index() < self.num_columns);
-        let (start, _) = self.range(row);
-        let (word_index, mask) = word_index_and_mask(column);
-        (self.words[start + word_index] & mask) != 0
-    }
-
-    /// Returns those indices that are true in rows `a` and `b`. This
-    /// is an O(n) operation where `n` is the number of elements
-    /// (somewhat independent from the actual size of the
-    /// intersection, in particular).
-    pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> {
-        assert!(row1.index() < self.num_rows && row2.index() < self.num_rows);
-        let (row1_start, row1_end) = self.range(row1);
-        let (row2_start, row2_end) = self.range(row2);
-        let mut result = Vec::with_capacity(self.num_columns);
-        for (base, (i, j)) in (row1_start..row1_end).zip(row2_start..row2_end).enumerate() {
-            let mut v = self.words[i] & self.words[j];
-            for bit in 0..WORD_BITS {
-                if v == 0 {
-                    break;
-                }
-                if v & 0x1 != 0 {
-                    result.push(C::new(base * WORD_BITS + bit));
-                }
-                v >>= 1;
-            }
-        }
-        result
-    }
-
-    /// Adds the bits from row `read` to the bits from row `write`, and
-    /// returns `true` if anything changed.
-    ///
-    /// This is used when computing transitive reachability because if
-    /// you have an edge `write -> read`, because in that case
-    /// `write` can reach everything that `read` can (and
-    /// potentially more).
-    pub fn union_rows(&mut self, read: R, write: R) -> bool {
-        assert!(read.index() < self.num_rows && write.index() < self.num_rows);
-        let (read_start, read_end) = self.range(read);
-        let (write_start, write_end) = self.range(write);
-        let words = &mut self.words[..];
-        let mut changed = false;
-        for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) {
-            let word = words[write_index];
-            let new_word = word | words[read_index];
-            words[write_index] = new_word;
-            changed |= word != new_word;
-        }
-        changed
-    }
-
-    /// Adds the bits from `with` to the bits from row `write`, and
-    /// returns `true` if anything changed.
-    pub fn union_row_with(&mut self, with: &BitSet<C>, write: R) -> bool {
-        assert!(write.index() < self.num_rows);
-        assert_eq!(with.domain_size(), self.num_columns);
-        let (write_start, write_end) = self.range(write);
-        let mut changed = false;
-        for (read_index, write_index) in (0..with.words().len()).zip(write_start..write_end) {
-            let word = self.words[write_index];
-            let new_word = word | with.words()[read_index];
-            self.words[write_index] = new_word;
-            changed |= word != new_word;
-        }
-        changed
-    }
-
-    /// Sets every cell in `row` to true.
-    pub fn insert_all_into_row(&mut self, row: R) {
-        assert!(row.index() < self.num_rows);
-        let (start, end) = self.range(row);
-        let words = &mut self.words[..];
-        for index in start..end {
-            words[index] = !0;
-        }
-        self.clear_excess_bits(row);
-    }
-
-    /// Clear excess bits in the final word of the row.
-    fn clear_excess_bits(&mut self, row: R) {
-        let num_bits_in_final_word = self.num_columns % WORD_BITS;
-        if num_bits_in_final_word > 0 {
-            let mask = (1 << num_bits_in_final_word) - 1;
-            let (_, end) = self.range(row);
-            let final_word_idx = end - 1;
-            self.words[final_word_idx] &= mask;
-        }
-    }
-
-    /// Gets a slice of the underlying words.
-    pub fn words(&self) -> &[Word] {
-        &self.words
-    }
-
-    /// Iterates through all the columns set to true in a given row of
-    /// the matrix.
-    pub fn iter(&self, row: R) -> BitIter<'_, C> {
-        assert!(row.index() < self.num_rows);
-        let (start, end) = self.range(row);
-        BitIter {
-            cur: None,
-            iter: self.words[start..end].iter().enumerate(),
-            marker: PhantomData,
-        }
-    }
-
-    /// Returns the number of elements in `row`.
-    pub fn count(&self, row: R) -> usize {
-        let (start, end) = self.range(row);
-        self.words[start..end].iter().map(|e| e.count_ones() as usize).sum()
-    }
-}
-
-/// A fixed-column-size, variable-row-size 2D bit matrix with a moderately
-/// sparse representation.
-///
-/// Initially, every row has no explicit representation. If any bit within a
-/// row is set, the entire row is instantiated as `Some(<HybridBitSet>)`.
-/// Furthermore, any previously uninstantiated rows prior to it will be
-/// instantiated as `None`. Those prior rows may themselves become fully
-/// instantiated later on if any of their bits are set.
-///
-/// `R` and `C` are index types used to identify rows and columns respectively;
-/// typically newtyped `usize` wrappers, but they can also just be `usize`.
-#[derive(Clone, Debug)]
-pub struct SparseBitMatrix<R, C>
-where
-    R: Idx,
-    C: Idx,
-{
-    num_columns: usize,
-    rows: IndexVec<R, Option<HybridBitSet<C>>>,
-}
-
-impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
-    /// Creates a new empty sparse bit matrix with no rows or columns.
-    pub fn new(num_columns: usize) -> Self {
-        Self {
-            num_columns,
-            rows: IndexVec::new(),
-        }
-    }
-
-    fn ensure_row(&mut self, row: R) -> &mut HybridBitSet<C> {
-        // Instantiate any missing rows up to and including row `row` with an
-        // empty HybridBitSet.
-        self.rows.ensure_contains_elem(row, || None);
-
-        // Then replace row `row` with a full HybridBitSet if necessary.
-        let num_columns = self.num_columns;
-        self.rows[row].get_or_insert_with(|| HybridBitSet::new_empty(num_columns))
-    }
-
-    /// Sets the cell at `(row, column)` to true. Put another way, insert
-    /// `column` to the bitset for `row`.
-    ///
-    /// Returns `true` if this changed the matrix.
-    pub fn insert(&mut self, row: R, column: C) -> bool {
-        self.ensure_row(row).insert(column)
-    }
-
-    /// Do the bits from `row` contain `column`? Put another way, is
-    /// the matrix cell at `(row, column)` true?  Put yet another way,
-    /// if the matrix represents (transitive) reachability, can
-    /// `row` reach `column`?
-    pub fn contains(&self, row: R, column: C) -> bool {
-        self.row(row).map_or(false, |r| r.contains(column))
-    }
-
-    /// Adds the bits from row `read` to the bits from row `write`, and
-    /// returns `true` if anything changed.
-    ///
-    /// This is used when computing transitive reachability because if
-    /// you have an edge `write -> read`, because in that case
-    /// `write` can reach everything that `read` can (and
-    /// potentially more).
-    pub fn union_rows(&mut self, read: R, write: R) -> bool {
-        if read == write || self.row(read).is_none() {
-            return false;
-        }
-
-        self.ensure_row(write);
-        if let (Some(read_row), Some(write_row)) = self.rows.pick2_mut(read, write) {
-            write_row.union(read_row)
-        } else {
-            unreachable!()
-        }
-    }
-
-    /// Union a row, `from`, into the `into` row.
-    pub fn union_into_row(&mut self, into: R, from: &HybridBitSet<C>) -> bool {
-        self.ensure_row(into).union(from)
-    }
-
-    /// Insert all bits in the given row.
-    pub fn insert_all_into_row(&mut self, row: R) {
-        self.ensure_row(row).insert_all();
-    }
-
-    pub fn rows(&self) -> impl Iterator<Item = R> {
-        self.rows.indices()
-    }
-
-    /// Iterates through all the columns set to true in a given row of
-    /// the matrix.
-    pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
-        self.row(row).into_iter().flat_map(|r| r.iter())
-    }
-
-    pub fn row(&self, row: R) -> Option<&HybridBitSet<C>> {
-        if let Some(Some(row)) = self.rows.get(row) {
-            Some(row)
-        } else {
-            None
-        }
-    }
-}
-
-#[inline]
-fn num_words<T: Idx>(domain_size: T) -> usize {
-    (domain_size.index() + WORD_BITS - 1) / WORD_BITS
-}
-
-#[inline]
-fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
-    let elem = elem.index();
-    let word_index = elem / WORD_BITS;
-    let mask = 1 << (elem % WORD_BITS);
-    (word_index, mask)
-}
diff --git a/src/librustc_data_structures/bit_set/tests.rs b/src/librustc_data_structures/bit_set/tests.rs
deleted file mode 100644 (file)
index ac79138..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-use super::*;
-
-extern crate test;
-use test::Bencher;
-
-#[test]
-fn test_new_filled() {
-    for i in 0..128 {
-        let idx_buf = BitSet::new_filled(i);
-        let elems: Vec<usize> = idx_buf.iter().collect();
-        let expected: Vec<usize> = (0..i).collect();
-        assert_eq!(elems, expected);
-    }
-}
-
-#[test]
-fn bitset_iter_works() {
-    let mut bitset: BitSet<usize> = BitSet::new_empty(100);
-    bitset.insert(1);
-    bitset.insert(10);
-    bitset.insert(19);
-    bitset.insert(62);
-    bitset.insert(63);
-    bitset.insert(64);
-    bitset.insert(65);
-    bitset.insert(66);
-    bitset.insert(99);
-    assert_eq!(
-        bitset.iter().collect::<Vec<_>>(),
-        [1, 10, 19, 62, 63, 64, 65, 66, 99]
-    );
-}
-
-#[test]
-fn bitset_iter_works_2() {
-    let mut bitset: BitSet<usize> = BitSet::new_empty(320);
-    bitset.insert(0);
-    bitset.insert(127);
-    bitset.insert(191);
-    bitset.insert(255);
-    bitset.insert(319);
-    assert_eq!(bitset.iter().collect::<Vec<_>>(), [0, 127, 191, 255, 319]);
-}
-
-#[test]
-fn union_two_sets() {
-    let mut set1: BitSet<usize> = BitSet::new_empty(65);
-    let mut set2: BitSet<usize> = BitSet::new_empty(65);
-    assert!(set1.insert(3));
-    assert!(!set1.insert(3));
-    assert!(set2.insert(5));
-    assert!(set2.insert(64));
-    assert!(set1.union(&set2));
-    assert!(!set1.union(&set2));
-    assert!(set1.contains(3));
-    assert!(!set1.contains(4));
-    assert!(set1.contains(5));
-    assert!(!set1.contains(63));
-    assert!(set1.contains(64));
-}
-
-#[test]
-fn hybrid_bitset() {
-    let mut sparse038: HybridBitSet<usize> = HybridBitSet::new_empty(256);
-    assert!(sparse038.is_empty());
-    assert!(sparse038.insert(0));
-    assert!(sparse038.insert(1));
-    assert!(sparse038.insert(8));
-    assert!(sparse038.insert(3));
-    assert!(!sparse038.insert(3));
-    assert!(sparse038.remove(1));
-    assert!(!sparse038.is_empty());
-    assert_eq!(sparse038.iter().collect::<Vec<_>>(), [0, 3, 8]);
-
-    for i in 0..256 {
-        if i == 0 || i == 3 || i == 8 {
-            assert!(sparse038.contains(i));
-        } else {
-            assert!(!sparse038.contains(i));
-        }
-    }
-
-    let mut sparse01358 = sparse038.clone();
-    assert!(sparse01358.insert(1));
-    assert!(sparse01358.insert(5));
-    assert_eq!(sparse01358.iter().collect::<Vec<_>>(), [0, 1, 3, 5, 8]);
-
-    let mut dense10 = HybridBitSet::new_empty(256);
-    for i in 0..10 {
-        assert!(dense10.insert(i));
-    }
-    assert!(!dense10.is_empty());
-    assert_eq!(dense10.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
-
-    let mut dense256 = HybridBitSet::new_empty(256);
-    assert!(dense256.is_empty());
-    dense256.insert_all();
-    assert!(!dense256.is_empty());
-    for i in 0..256 {
-        assert!(dense256.contains(i));
-    }
-
-    assert!(sparse038.superset(&sparse038));    // sparse + sparse (self)
-    assert!(sparse01358.superset(&sparse038));  // sparse + sparse
-    assert!(dense10.superset(&sparse038));      // dense + sparse
-    assert!(dense10.superset(&dense10));        // dense + dense (self)
-    assert!(dense256.superset(&dense10));       // dense + dense
-
-    let mut hybrid = sparse038;
-    assert!(!sparse01358.union(&hybrid));       // no change
-    assert!(hybrid.union(&sparse01358));
-    assert!(hybrid.superset(&sparse01358) && sparse01358.superset(&hybrid));
-    assert!(!dense10.union(&sparse01358));
-    assert!(!dense256.union(&dense10));
-    let mut dense = dense10;
-    assert!(dense.union(&dense256));
-    assert!(dense.superset(&dense256) && dense256.superset(&dense));
-    assert!(hybrid.union(&dense256));
-    assert!(hybrid.superset(&dense256) && dense256.superset(&hybrid));
-
-    assert_eq!(dense256.iter().count(), 256);
-    let mut dense0 = dense256;
-    for i in 0..256 {
-        assert!(dense0.remove(i));
-    }
-    assert!(!dense0.remove(0));
-    assert!(dense0.is_empty());
-}
-
-#[test]
-fn grow() {
-    let mut set: GrowableBitSet<usize> = GrowableBitSet::with_capacity(65);
-    for index in 0..65 {
-        assert!(set.insert(index));
-        assert!(!set.insert(index));
-    }
-    set.ensure(128);
-
-    // Check if the bits set before growing are still set
-    for index in 0..65 {
-        assert!(set.contains(index));
-    }
-
-    // Check if the new bits are all un-set
-    for index in 65..128 {
-        assert!(!set.contains(index));
-    }
-
-    // Check that we can set all new bits without running out of bounds
-    for index in 65..128 {
-        assert!(set.insert(index));
-        assert!(!set.insert(index));
-    }
-}
-
-#[test]
-fn matrix_intersection() {
-    let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(200, 200);
-
-    // (*) Elements reachable from both 2 and 65.
-
-    matrix.insert(2, 3);
-    matrix.insert(2, 6);
-    matrix.insert(2, 10); // (*)
-    matrix.insert(2, 64); // (*)
-    matrix.insert(2, 65);
-    matrix.insert(2, 130);
-    matrix.insert(2, 160); // (*)
-
-    matrix.insert(64, 133);
-
-    matrix.insert(65, 2);
-    matrix.insert(65, 8);
-    matrix.insert(65, 10); // (*)
-    matrix.insert(65, 64); // (*)
-    matrix.insert(65, 68);
-    matrix.insert(65, 133);
-    matrix.insert(65, 160); // (*)
-
-    let intersection = matrix.intersect_rows(2, 64);
-    assert!(intersection.is_empty());
-
-    let intersection = matrix.intersect_rows(2, 65);
-    assert_eq!(intersection, &[10, 64, 160]);
-}
-
-#[test]
-fn matrix_iter() {
-    let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(64, 100);
-    matrix.insert(3, 22);
-    matrix.insert(3, 75);
-    matrix.insert(2, 99);
-    matrix.insert(4, 0);
-    matrix.union_rows(3, 5);
-    matrix.insert_all_into_row(6);
-
-    let expected = [99];
-    let mut iter = expected.iter();
-    for i in matrix.iter(2) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-
-    let expected = [22, 75];
-    let mut iter = expected.iter();
-    assert_eq!(matrix.count(3), expected.len());
-    for i in matrix.iter(3) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-
-    let expected = [0];
-    let mut iter = expected.iter();
-    assert_eq!(matrix.count(4), expected.len());
-    for i in matrix.iter(4) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-
-    let expected = [22, 75];
-    let mut iter = expected.iter();
-    assert_eq!(matrix.count(5), expected.len());
-    for i in matrix.iter(5) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-
-    assert_eq!(matrix.count(6), 100);
-    let mut count = 0;
-    for (idx, i) in matrix.iter(6).enumerate() {
-        assert_eq!(idx, i);
-        count += 1;
-    }
-    assert_eq!(count, 100);
-
-    if let Some(i) = matrix.iter(7).next() {
-        panic!("expected no elements in row, but contains element {:?}", i);
-    }
-}
-
-#[test]
-fn sparse_matrix_iter() {
-    let mut matrix: SparseBitMatrix<usize, usize> = SparseBitMatrix::new(100);
-    matrix.insert(3, 22);
-    matrix.insert(3, 75);
-    matrix.insert(2, 99);
-    matrix.insert(4, 0);
-    matrix.union_rows(3, 5);
-
-    let expected = [99];
-    let mut iter = expected.iter();
-    for i in matrix.iter(2) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-
-    let expected = [22, 75];
-    let mut iter = expected.iter();
-    for i in matrix.iter(3) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-
-    let expected = [0];
-    let mut iter = expected.iter();
-    for i in matrix.iter(4) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-
-    let expected = [22, 75];
-    let mut iter = expected.iter();
-    for i in matrix.iter(5) {
-        let j = *iter.next().unwrap();
-        assert_eq!(i, j);
-    }
-    assert!(iter.next().is_none());
-}
-
-/// Merge dense hybrid set into empty sparse hybrid set.
-#[bench]
-fn union_hybrid_sparse_empty_to_dense(b: &mut Bencher) {
-    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(256);
-    for i in 0..10 {
-        assert!(pre_dense.insert(i));
-    }
-    let pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(256);
-    b.iter(|| {
-        let dense = pre_dense.clone();
-        let mut sparse = pre_sparse.clone();
-        sparse.union(&dense);
-    })
-}
-
-/// Merge dense hybrid set into full hybrid set with same indices.
-#[bench]
-fn union_hybrid_sparse_full_to_dense(b: &mut Bencher) {
-    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(256);
-    for i in 0..10 {
-        assert!(pre_dense.insert(i));
-    }
-    let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(256);
-    for i in 0..SPARSE_MAX {
-        assert!(pre_sparse.insert(i));
-    }
-    b.iter(|| {
-        let dense = pre_dense.clone();
-        let mut sparse = pre_sparse.clone();
-        sparse.union(&dense);
-    })
-}
-
-/// Merge dense hybrid set into full hybrid set with indices over the whole domain.
-#[bench]
-fn union_hybrid_sparse_domain_to_dense(b: &mut Bencher) {
-    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX*64);
-    for i in 0..10 {
-        assert!(pre_dense.insert(i));
-    }
-    let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX*64);
-    for i in 0..SPARSE_MAX {
-        assert!(pre_sparse.insert(i*64));
-    }
-    b.iter(|| {
-        let dense = pre_dense.clone();
-        let mut sparse = pre_sparse.clone();
-        sparse.union(&dense);
-    })
-}
-
-/// Merge dense hybrid set into empty hybrid set where the domain is very small.
-#[bench]
-fn union_hybrid_sparse_empty_small_domain(b: &mut Bencher) {
-    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
-    for i in 0..SPARSE_MAX {
-        assert!(pre_dense.insert(i));
-    }
-    let pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
-    b.iter(|| {
-        let dense = pre_dense.clone();
-        let mut sparse = pre_sparse.clone();
-        sparse.union(&dense);
-    })
-}
-
-/// Merge dense hybrid set into full hybrid set where the domain is very small.
-#[bench]
-fn union_hybrid_sparse_full_small_domain(b: &mut Bencher) {
-    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
-    for i in 0..SPARSE_MAX {
-        assert!(pre_dense.insert(i));
-    }
-    let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
-    for i in 0..SPARSE_MAX {
-        assert!(pre_sparse.insert(i));
-    }
-    b.iter(|| {
-        let dense = pre_dense.clone();
-        let mut sparse = pre_sparse.clone();
-        sparse.union(&dense);
-    })
-}
index 41e6b72953e83211d8dbe9d4ba61c815f071e89a..29a8a98d229cc7ec9810dad8890ae378b45cd16d 100644 (file)
@@ -4,7 +4,7 @@
 //! Rice Computer Science TS-06-33870
 //! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>
 
-use super::super::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use super::iterate::reverse_post_order;
 use super::ControlFlowGraph;
 
index d2699004c81d8f9952d9ebd65952142d2ee39d73..052a09c0774b69336a6b56d4680766472a317ddb 100644 (file)
@@ -20,7 +20,7 @@
 //! the field `next_edge`). Each of those fields is an array that should
 //! be indexed by the direction (see the type `Direction`).
 
-use crate::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use crate::snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
 use std::fmt::Debug;
 use std::usize;
index cbf6a0a3c03a0810d9c42a4ebe53210569ee99c1..e268b28174474a8df998bb841df6a522eead1c7a 100644 (file)
@@ -1,6 +1,6 @@
-use super::super::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use super::{DirectedGraph, WithNumNodes, WithSuccessors, WithStartNode};
-use crate::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 
 #[cfg(test)]
 mod tests;
index 0a607659f3e246233bc74988269806fee7a9e44e..37335799d19af87ae5d46b1e469a41bc0aa9a0e6 100644 (file)
@@ -1,4 +1,4 @@
-use super::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 
 pub mod dominators;
 pub mod implementation;
index 23a1a2a90a4d52fee2f6fff34f76ab1e023b3056..c214f66cd15cd1dc47a21768a1425b5cb702244d 100644 (file)
@@ -6,7 +6,7 @@
 use crate::fx::FxHashSet;
 use crate::graph::{DirectedGraph, WithNumNodes, WithNumEdges, WithSuccessors, GraphSuccessors};
 use crate::graph::vec_graph::VecGraph;
-use crate::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use std::ops::Range;
 
 #[cfg(test)]
index 19c61f2680d1d9a5dba559462f3000d7b4af143b..aad5944dcd0be0b8a2a75e782628f2ff48894c11 100644 (file)
@@ -1,4 +1,4 @@
-use crate::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use crate::graph::{DirectedGraph, WithNumNodes, WithNumEdges, WithSuccessors, GraphSuccessors};
 
 #[cfg(test)]
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
deleted file mode 100644 (file)
index 6e80b48..0000000
+++ /dev/null
@@ -1,830 +0,0 @@
-use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
-
-use std::fmt::Debug;
-use std::iter::{self, FromIterator};
-use std::slice;
-use std::marker::PhantomData;
-use std::ops::{Index, IndexMut, Range, RangeBounds};
-use std::fmt;
-use std::hash::Hash;
-use std::vec;
-use std::u32;
-
-/// Represents some newtyped `usize` wrapper.
-///
-/// Purpose: avoid mixing indexes for different bitvector domains.
-pub trait Idx: Copy + 'static + Ord + Debug + Hash {
-    fn new(idx: usize) -> Self;
-
-    fn index(self) -> usize;
-
-    fn increment_by(&mut self, amount: usize) {
-        *self = self.plus(amount);
-    }
-
-    fn plus(self, amount: usize) -> Self {
-        Self::new(self.index() + amount)
-    }
-}
-
-impl Idx for usize {
-    #[inline]
-    fn new(idx: usize) -> Self { idx }
-    #[inline]
-    fn index(self) -> usize { self }
-}
-
-impl Idx for u32 {
-    #[inline]
-    fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 }
-    #[inline]
-    fn index(self) -> usize { self as usize }
-}
-
-/// Creates a struct type `S` that can be used as an index with
-/// `IndexVec` and so on.
-///
-/// There are two ways of interacting with these indices:
-///
-/// - The `From` impls are the preferred way. So you can do
-///   `S::from(v)` with a `usize` or `u32`. And you can convert back
-///   to an integer with `u32::from(s)`.
-///
-/// - Alternatively, you can use the methods `S::new(v)` and `s.index()`
-///   to create/return a value.
-///
-/// Internally, the index uses a u32, so the index must not exceed
-/// `u32::MAX`. You can also customize things like the `Debug` impl,
-/// what traits are derived, and so forth via the macro.
-#[macro_export]
-#[allow_internal_unstable(step_trait, rustc_attrs)]
-macro_rules! newtype_index {
-    // ---- public rules ----
-
-    // Use default constants
-    ($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => (
-        $crate::newtype_index!(
-            // Leave out derives marker so we can use its absence to ensure it comes first
-            @attrs        [$(#[$attrs])*]
-            @type         [$name]
-            // shave off 256 indices at the end to allow space for packing these indices into enums
-            @max          [0xFFFF_FF00]
-            @vis          [$v]
-            @debug_format ["{}"]);
-    );
-
-    // Define any constants
-    ($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => (
-        $crate::newtype_index!(
-            // Leave out derives marker so we can use its absence to ensure it comes first
-            @attrs        [$(#[$attrs])*]
-            @type         [$name]
-            // shave off 256 indices at the end to allow space for packing these indices into enums
-            @max          [0xFFFF_FF00]
-            @vis          [$v]
-            @debug_format ["{}"]
-                          $($tokens)+);
-    );
-
-    // ---- private rules ----
-
-    // Base case, user-defined constants (if any) have already been defined
-    (@derives      [$($derives:ident,)*]
-     @attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]) => (
-        $(#[$attrs])*
-        #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
-        #[rustc_layout_scalar_valid_range_end($max)]
-        $v struct $type {
-            private: u32
-        }
-
-        impl Clone for $type {
-            fn clone(&self) -> Self {
-                *self
-            }
-        }
-
-        impl $type {
-            $v const MAX_AS_U32: u32 = $max;
-
-            $v const MAX: $type = $type::from_u32_const($max);
-
-            #[inline]
-            $v fn from_usize(value: usize) -> Self {
-                assert!(value <= ($max as usize));
-                unsafe {
-                    $type::from_u32_unchecked(value as u32)
-                }
-            }
-
-            #[inline]
-            $v fn from_u32(value: u32) -> Self {
-                assert!(value <= $max);
-                unsafe {
-                    $type::from_u32_unchecked(value)
-                }
-            }
-
-            /// Hacky variant of `from_u32` for use in constants.
-            /// This version checks the "max" constraint by using an
-            /// invalid array dereference.
-            #[inline]
-            $v const fn from_u32_const(value: u32) -> Self {
-                // This will fail at const eval time unless `value <=
-                // max` is true (in which case we get the index 0).
-                // It will also fail at runtime, of course, but in a
-                // kind of wacky way.
-                let _ = ["out of range value used"][
-                    !(value <= $max) as usize
-                ];
-
-                unsafe {
-                    $type { private: value }
-                }
-            }
-
-            #[inline]
-            $v const unsafe fn from_u32_unchecked(value: u32) -> Self {
-                $type { private: value }
-            }
-
-            /// Extracts the value of this index as an integer.
-            #[inline]
-            $v fn index(self) -> usize {
-                self.as_usize()
-            }
-
-            /// Extracts the value of this index as a `u32`.
-            #[inline]
-            $v fn as_u32(self) -> u32 {
-                self.private
-            }
-
-            /// Extracts the value of this index as a `usize`.
-            #[inline]
-            $v fn as_usize(self) -> usize {
-                self.as_u32() as usize
-            }
-        }
-
-        impl std::ops::Add<usize> for $type {
-            type Output = Self;
-
-            fn add(self, other: usize) -> Self {
-                Self::new(self.index() + other)
-            }
-        }
-
-        impl Idx for $type {
-            #[inline]
-            fn new(value: usize) -> Self {
-                Self::from(value)
-            }
-
-            #[inline]
-            fn index(self) -> usize {
-                usize::from(self)
-            }
-        }
-
-        impl ::std::iter::Step for $type {
-            #[inline]
-            fn steps_between(start: &Self, end: &Self) -> Option<usize> {
-                <usize as ::std::iter::Step>::steps_between(
-                    &Idx::index(*start),
-                    &Idx::index(*end),
-                )
-            }
-
-            #[inline]
-            fn replace_one(&mut self) -> Self {
-                ::std::mem::replace(self, Self::new(1))
-            }
-
-            #[inline]
-            fn replace_zero(&mut self) -> Self {
-                ::std::mem::replace(self, Self::new(0))
-            }
-
-            #[inline]
-            fn add_one(&self) -> Self {
-                Self::new(Idx::index(*self) + 1)
-            }
-
-            #[inline]
-            fn sub_one(&self) -> Self {
-                Self::new(Idx::index(*self) - 1)
-            }
-
-            #[inline]
-            fn add_usize(&self, u: usize) -> Option<Self> {
-                Idx::index(*self).checked_add(u).map(Self::new)
-            }
-
-            #[inline]
-            fn sub_usize(&self, u: usize) -> Option<Self> {
-                Idx::index(*self).checked_sub(u).map(Self::new)
-            }
-        }
-
-        impl From<$type> for u32 {
-            #[inline]
-            fn from(v: $type) -> u32 {
-                v.as_u32()
-            }
-        }
-
-        impl From<$type> for usize {
-            #[inline]
-            fn from(v: $type) -> usize {
-                v.as_usize()
-            }
-        }
-
-        impl From<usize> for $type {
-            #[inline]
-            fn from(value: usize) -> Self {
-                $type::from_usize(value)
-            }
-        }
-
-        impl From<u32> for $type {
-            #[inline]
-            fn from(value: u32) -> Self {
-                $type::from_u32(value)
-            }
-        }
-
-        $crate::newtype_index!(
-            @handle_debug
-            @derives      [$($derives,)*]
-            @type         [$type]
-            @debug_format [$debug_format]);
-    );
-
-    // base case for handle_debug where format is custom. No Debug implementation is emitted.
-    (@handle_debug
-     @derives      [$($_derives:ident,)*]
-     @type         [$type:ident]
-     @debug_format [custom]) => ();
-
-    // base case for handle_debug, no debug overrides found, so use default
-    (@handle_debug
-     @derives      []
-     @type         [$type:ident]
-     @debug_format [$debug_format:tt]) => (
-        impl ::std::fmt::Debug for $type {
-            fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-                write!(fmt, $debug_format, self.as_u32())
-            }
-        }
-    );
-
-    // Debug is requested for derive, don't generate any Debug implementation.
-    (@handle_debug
-     @derives      [Debug, $($derives:ident,)*]
-     @type         [$type:ident]
-     @debug_format [$debug_format:tt]) => ();
-
-    // It's not Debug, so just pop it off the front of the derives stack and check the rest.
-    (@handle_debug
-     @derives      [$_derive:ident, $($derives:ident,)*]
-     @type         [$type:ident]
-     @debug_format [$debug_format:tt]) => (
-        $crate::newtype_index!(
-            @handle_debug
-            @derives      [$($derives,)*]
-            @type         [$type]
-            @debug_format [$debug_format]);
-    );
-
-    // Append comma to end of derives list if it's missing
-    (@attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   derive [$($derives:ident),*]
-                   $($tokens:tt)*) => (
-        $crate::newtype_index!(
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          derive [$($derives,)*]
-                          $($tokens)*);
-    );
-
-    // By not including the @derives marker in this list nor in the default args, we can force it
-    // to come first if it exists. When encodable is custom, just use the derives list as-is.
-    (@attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   derive [$($derives:ident,)+]
-                   ENCODABLE = custom
-                   $($tokens:tt)*) => (
-        $crate::newtype_index!(
-            @attrs        [$(#[$attrs])*]
-            @derives      [$($derives,)+]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $($tokens)*);
-    );
-
-    // By not including the @derives marker in this list nor in the default args, we can force it
-    // to come first if it exists. When encodable isn't custom, add serialization traits by default.
-    (@attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   derive [$($derives:ident,)+]
-                   $($tokens:tt)*) => (
-        $crate::newtype_index!(
-            @derives      [$($derives,)+ RustcEncodable,]
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $($tokens)*);
-        $crate::newtype_index!(@decodable $type);
-    );
-
-    // The case where no derives are added, but encodable is overridden. Don't
-    // derive serialization traits
-    (@attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   ENCODABLE = custom
-                   $($tokens:tt)*) => (
-        $crate::newtype_index!(
-            @derives      []
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $($tokens)*);
-    );
-
-    // The case where no derives are added, add serialization derives by default
-    (@attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   $($tokens:tt)*) => (
-        $crate::newtype_index!(
-            @derives      [RustcEncodable,]
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $($tokens)*);
-        $crate::newtype_index!(@decodable $type);
-    );
-
-    (@decodable $type:ident) => (
-        impl ::rustc_serialize::Decodable for $type {
-            fn decode<D: ::rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
-                d.read_u32().map(Self::from)
-            }
-        }
-    );
-
-    // Rewrite final without comma to one that includes comma
-    (@derives      [$($derives:ident,)*]
-     @attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   $name:ident = $constant:expr) => (
-        $crate::newtype_index!(
-            @derives      [$($derives,)*]
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $name = $constant,);
-    );
-
-    // Rewrite final const without comma to one that includes comma
-    (@derives      [$($derives:ident,)*]
-     @attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   $(#[doc = $doc:expr])*
-                   const $name:ident = $constant:expr) => (
-        $crate::newtype_index!(
-            @derives      [$($derives,)*]
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $(#[doc = $doc])* const $name = $constant,);
-    );
-
-    // Replace existing default for max
-    (@derives      [$($derives:ident,)*]
-     @attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$_max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   MAX = $max:expr,
-                   $($tokens:tt)*) => (
-        $crate::newtype_index!(
-            @derives      [$($derives,)*]
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $($tokens)*);
-    );
-
-    // Replace existing default for debug_format
-    (@derives      [$($derives:ident,)*]
-     @attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$_debug_format:tt]
-                   DEBUG_FORMAT = $debug_format:tt,
-                   $($tokens:tt)*) => (
-        $crate::newtype_index!(
-            @derives      [$($derives,)*]
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $($tokens)*);
-    );
-
-    // Assign a user-defined constant
-    (@derives      [$($derives:ident,)*]
-     @attrs        [$(#[$attrs:meta])*]
-     @type         [$type:ident]
-     @max          [$max:expr]
-     @vis          [$v:vis]
-     @debug_format [$debug_format:tt]
-                   $(#[doc = $doc:expr])*
-                   const $name:ident = $constant:expr,
-                   $($tokens:tt)*) => (
-        $(#[doc = $doc])*
-        pub const $name: $type = $type::from_u32_const($constant);
-        $crate::newtype_index!(
-            @derives      [$($derives,)*]
-            @attrs        [$(#[$attrs])*]
-            @type         [$type]
-            @max          [$max]
-            @vis          [$v]
-            @debug_format [$debug_format]
-                          $($tokens)*);
-    );
-}
-
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct IndexVec<I: Idx, T> {
-    pub raw: Vec<T>,
-    _marker: PhantomData<fn(&I)>
-}
-
-// Whether `IndexVec` is `Send` depends only on the data,
-// not the phantom data.
-unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {}
-
-impl<I: Idx, T: Encodable> Encodable for IndexVec<I, T> {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        Encodable::encode(&self.raw, s)
-    }
-}
-
-impl<I: Idx, T: Decodable> Decodable for IndexVec<I, T> {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
-        Decodable::decode(d).map(|v| {
-            IndexVec { raw: v, _marker: PhantomData }
-        })
-    }
-}
-
-impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&self.raw, fmt)
-    }
-}
-
-pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
-
-impl<I: Idx, T> IndexVec<I, T> {
-    #[inline]
-    pub fn new() -> Self {
-        IndexVec { raw: Vec::new(), _marker: PhantomData }
-    }
-
-    #[inline]
-    pub fn from_raw(raw: Vec<T>) -> Self {
-        IndexVec { raw, _marker: PhantomData }
-    }
-
-    #[inline]
-    pub fn with_capacity(capacity: usize) -> Self {
-        IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData }
-    }
-
-    #[inline]
-    pub fn from_elem<S>(elem: T, universe: &IndexVec<I, S>) -> Self
-        where T: Clone
-    {
-        IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData }
-    }
-
-    #[inline]
-    pub fn from_elem_n(elem: T, n: usize) -> Self
-        where T: Clone
-    {
-        IndexVec { raw: vec![elem; n], _marker: PhantomData }
-    }
-
-    #[inline]
-    pub fn push(&mut self, d: T) -> I {
-        let idx = I::new(self.len());
-        self.raw.push(d);
-        idx
-    }
-
-    #[inline]
-    pub fn pop(&mut self) -> Option<T> {
-        self.raw.pop()
-    }
-
-    #[inline]
-    pub fn len(&self) -> usize {
-        self.raw.len()
-    }
-
-    /// Gives the next index that will be assigned when `push` is
-    /// called.
-    #[inline]
-    pub fn next_index(&self) -> I {
-        I::new(self.len())
-    }
-
-    #[inline]
-    pub fn is_empty(&self) -> bool {
-        self.raw.is_empty()
-    }
-
-    #[inline]
-    pub fn into_iter(self) -> vec::IntoIter<T> {
-        self.raw.into_iter()
-    }
-
-    #[inline]
-    pub fn into_iter_enumerated(self) -> Enumerated<I, vec::IntoIter<T>>
-    {
-        self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData })
-    }
-
-    #[inline]
-    pub fn iter(&self) -> slice::Iter<'_, T> {
-        self.raw.iter()
-    }
-
-    #[inline]
-    pub fn iter_enumerated(&self) -> Enumerated<I, slice::Iter<'_, T>>
-    {
-        self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData })
-    }
-
-    #[inline]
-    pub fn indices(&self) -> iter::Map<Range<usize>, IntoIdx<I>> {
-        (0..self.len()).map(IntoIdx { _marker: PhantomData })
-    }
-
-    #[inline]
-    pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
-        self.raw.iter_mut()
-    }
-
-    #[inline]
-    pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<'_, T>>
-    {
-        self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData })
-    }
-
-    #[inline]
-    pub fn drain<'a, R: RangeBounds<usize>>(
-        &'a mut self, range: R) -> impl Iterator<Item=T> + 'a {
-        self.raw.drain(range)
-    }
-
-    #[inline]
-    pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
-        &'a mut self, range: R) -> impl Iterator<Item=(I, T)> + 'a {
-        self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData })
-    }
-
-    #[inline]
-    pub fn last(&self) -> Option<I> {
-        self.len().checked_sub(1).map(I::new)
-    }
-
-    #[inline]
-    pub fn shrink_to_fit(&mut self) {
-        self.raw.shrink_to_fit()
-    }
-
-    #[inline]
-    pub fn swap(&mut self, a: I, b: I) {
-        self.raw.swap(a.index(), b.index())
-    }
-
-    #[inline]
-    pub fn truncate(&mut self, a: usize) {
-        self.raw.truncate(a)
-    }
-
-    #[inline]
-    pub fn get(&self, index: I) -> Option<&T> {
-        self.raw.get(index.index())
-    }
-
-    #[inline]
-    pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
-        self.raw.get_mut(index.index())
-    }
-
-    /// Returns mutable references to two distinct elements, a and b. Panics if a == b.
-    #[inline]
-    pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
-        let (ai, bi) = (a.index(), b.index());
-        assert!(ai != bi);
-
-        if ai < bi {
-            let (c1, c2) = self.raw.split_at_mut(bi);
-            (&mut c1[ai], &mut c2[0])
-        } else {
-            let (c2, c1) = self.pick2_mut(b, a);
-            (c1, c2)
-        }
-    }
-
-    pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
-        IndexVec {
-            raw: self.raw,
-            _marker: PhantomData,
-        }
-    }
-}
-
-impl<I: Idx, T: Clone> IndexVec<I, T> {
-    /// Grows the index vector so that it contains an entry for
-    /// `elem`; if that is already true, then has no
-    /// effect. Otherwise, inserts new values as needed by invoking
-    /// `fill_value`.
-    #[inline]
-    pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
-        let min_new_len = elem.index() + 1;
-        if self.len() < min_new_len {
-            self.raw.resize_with(min_new_len, fill_value);
-        }
-    }
-
-    #[inline]
-    pub fn resize(&mut self, new_len: usize, value: T) {
-        self.raw.resize(new_len, value)
-    }
-
-    #[inline]
-    pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
-        let min_new_len = elem.index() + 1;
-        self.raw.resize_with(min_new_len, fill_value);
-    }
-}
-
-impl<I: Idx, T: Ord> IndexVec<I, T> {
-    #[inline]
-    pub fn binary_search(&self, value: &T) -> Result<I, I> {
-        match self.raw.binary_search(value) {
-            Ok(i) => Ok(Idx::new(i)),
-            Err(i) => Err(Idx::new(i)),
-        }
-    }
-}
-
-impl<I: Idx, T> Index<I> for IndexVec<I, T> {
-    type Output = T;
-
-    #[inline]
-    fn index(&self, index: I) -> &T {
-        &self.raw[index.index()]
-    }
-}
-
-impl<I: Idx, T> IndexMut<I> for IndexVec<I, T> {
-    #[inline]
-    fn index_mut(&mut self, index: I) -> &mut T {
-        &mut self.raw[index.index()]
-    }
-}
-
-impl<I: Idx, T> Default for IndexVec<I, T> {
-    #[inline]
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl<I: Idx, T> Extend<T> for IndexVec<I, T> {
-    #[inline]
-    fn extend<J: IntoIterator<Item = T>>(&mut self, iter: J) {
-        self.raw.extend(iter);
-    }
-}
-
-impl<I: Idx, T> FromIterator<T> for IndexVec<I, T> {
-    #[inline]
-    fn from_iter<J>(iter: J) -> Self where J: IntoIterator<Item=T> {
-        IndexVec { raw: FromIterator::from_iter(iter), _marker: PhantomData }
-    }
-}
-
-impl<I: Idx, T> IntoIterator for IndexVec<I, T> {
-    type Item = T;
-    type IntoIter = vec::IntoIter<T>;
-
-    #[inline]
-    fn into_iter(self) -> vec::IntoIter<T> {
-        self.raw.into_iter()
-    }
-
-}
-
-impl<'a, I: Idx, T> IntoIterator for &'a IndexVec<I, T> {
-    type Item = &'a T;
-    type IntoIter = slice::Iter<'a, T>;
-
-    #[inline]
-    fn into_iter(self) -> slice::Iter<'a, T> {
-        self.raw.iter()
-    }
-}
-
-impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> {
-    type Item = &'a mut T;
-    type IntoIter = slice::IterMut<'a, T>;
-
-    #[inline]
-    fn into_iter(self) -> slice::IterMut<'a, T> {
-        self.raw.iter_mut()
-    }
-}
-
-pub struct IntoIdx<I: Idx> { _marker: PhantomData<fn(&I)> }
-impl<I: Idx, T> FnOnce<((usize, T),)> for IntoIdx<I> {
-    type Output = (I, T);
-
-    extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output {
-        (I::new(n), t)
-    }
-}
-
-impl<I: Idx, T> FnMut<((usize, T),)> for IntoIdx<I> {
-    extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output {
-        (I::new(n), t)
-    }
-}
-
-impl<I: Idx> FnOnce<(usize,)> for IntoIdx<I> {
-    type Output = I;
-
-    extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output {
-        I::new(n)
-    }
-}
-
-impl<I: Idx> FnMut<(usize,)> for IntoIdx<I> {
-    extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output {
-        I::new(n)
-    }
-}
index d6e9c479c9b8dad1d1e5fb87763a8a406a480af4..474a42644d9150700bf2e47ce673ef3e04b04c7d 100644 (file)
@@ -68,14 +68,12 @@ macro_rules! unlikely {
 pub mod svh;
 pub mod base_n;
 pub mod binary_search_util;
-pub mod bit_set;
 pub mod box_region;
 pub mod const_cstr;
 pub mod flock;
 pub mod fx;
 pub mod stable_map;
 pub mod graph;
-pub mod indexed_vec;
 pub mod jobserver;
 pub mod obligation_forest;
 pub mod owning_ref;
index 1c7109fe500e083c5f5e694f021793e5de0ffac2..cfccef67fe7ddc66c9f65c3f3febb661f5ff0af4 100644 (file)
@@ -138,7 +138,7 @@ pub struct ObligationForest<O: ForestObligation> {
     /// call to `compress`.
     ///
     /// `usize` indices are used here and throughout this module, rather than
-    /// `newtype_index!` indices, because this code is hot enough that the
+    /// `rustc_index::newtype_index!` indices, because this code is hot enough that the
     /// `u32`-to-`usize` conversions that would be required are significant,
     /// and space considerations are not important.
     nodes: Vec<Node<O>>,
index 53dff794ff0ae6893c28f40c1455a15cbf523a0a..ee4f6a5e785e40c8351a7aa6dc549ecc6c9841ea 100644 (file)
@@ -2,8 +2,8 @@
 use std::mem;
 use smallvec::SmallVec;
 use crate::sip128::SipHasher128;
-use crate::indexed_vec;
-use crate::bit_set;
+use rustc_index::vec;
+use rustc_index::bit_set;
 
 /// When hashing something that ends up affecting properties like symbol names,
 /// we want these symbol names to be calculated independently of other factors
@@ -429,7 +429,7 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
-impl<I: indexed_vec::Idx, T, CTX> HashStable<CTX> for indexed_vec::IndexVec<I, T>
+impl<I: vec::Idx, T, CTX> HashStable<CTX> for vec::IndexVec<I, T>
     where T: HashStable<CTX>,
 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
@@ -441,14 +441,14 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
 }
 
 
-impl<I: indexed_vec::Idx, CTX> HashStable<CTX> for bit_set::BitSet<I>
+impl<I: vec::Idx, CTX> HashStable<CTX> for bit_set::BitSet<I>
 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.words().hash_stable(ctx, hasher);
     }
 }
 
-impl<R: indexed_vec::Idx, C: indexed_vec::Idx, CTX> HashStable<CTX>
+impl<R: vec::Idx, C: vec::Idx, CTX> HashStable<CTX>
 for bit_set::BitMatrix<R, C>
 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
index 9c5447f3f5a44a406162267ab8d0aab3de61a038..f0a9c3afc68b08e00fdf4fcdfbc9bb022b003eb4 100644 (file)
@@ -1,4 +1,4 @@
-use crate::bit_set::BitMatrix;
+use rustc_index::bit_set::BitMatrix;
 use crate::fx::FxHashMap;
 use crate::stable_hasher::{HashStable, StableHasher};
 use crate::sync::Lock;
index 0fb8060031843a156cf2344ec194a07bb6e95c09..7744c30655dce4b5e3167af355609d3dc7fac177 100644 (file)
@@ -1,4 +1,4 @@
-use crate::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 
 pub fn iter<Ls>(
     first: Option<Ls::LinkIndex>,
index 193025aafad20f9bf452b2fff07e67059f4ac3b8..af63b18e9e92284f04c3e9f2384b40fc2bbe59f7 100644 (file)
@@ -1,5 +1,5 @@
-use crate::bit_set::BitSet;
-use crate::indexed_vec::Idx;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::Idx;
 use std::collections::VecDeque;
 
 /// A work queue is a handy data structure for tracking work left to
diff --git a/src/librustc_index/Cargo.toml b/src/librustc_index/Cargo.toml
new file mode 100644 (file)
index 0000000..b1ebc95
--- /dev/null
@@ -0,0 +1,14 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_index"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_index"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+rustc_serialize = { path = "../libserialize", package = "serialize" }
+smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs
new file mode 100644 (file)
index 0000000..9c96645
--- /dev/null
@@ -0,0 +1,984 @@
+use crate::vec::{Idx, IndexVec};
+use smallvec::SmallVec;
+use std::fmt;
+use std::iter;
+use std::marker::PhantomData;
+use std::mem;
+use std::slice;
+
+#[cfg(test)]
+mod tests;
+
+pub type Word = u64;
+pub const WORD_BYTES: usize = mem::size_of::<Word>();
+pub const WORD_BITS: usize = WORD_BYTES * 8;
+
+/// A fixed-size bitset type with a dense representation. It does not support
+/// resizing after creation; use `GrowableBitSet` for that.
+///
+/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
+/// just be `usize`.
+///
+/// All operations that involve an element will panic if the element is equal
+/// to or greater than the domain size. All operations that involve two bitsets
+/// will panic if the bitsets have differing domain sizes.
+#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+pub struct BitSet<T: Idx> {
+    domain_size: usize,
+    words: Vec<Word>,
+    marker: PhantomData<T>,
+}
+
+impl<T: Idx> BitSet<T> {
+    /// Creates a new, empty bitset with a given `domain_size`.
+    #[inline]
+    pub fn new_empty(domain_size: usize) -> BitSet<T> {
+        let num_words = num_words(domain_size);
+        BitSet {
+            domain_size,
+            words: vec![0; num_words],
+            marker: PhantomData,
+        }
+    }
+
+    /// Creates a new, filled bitset with a given `domain_size`.
+    #[inline]
+    pub fn new_filled(domain_size: usize) -> BitSet<T> {
+        let num_words = num_words(domain_size);
+        let mut result = BitSet {
+            domain_size,
+            words: vec![!0; num_words],
+            marker: PhantomData,
+        };
+        result.clear_excess_bits();
+        result
+    }
+
+    /// Gets the domain size.
+    pub fn domain_size(&self) -> usize {
+        self.domain_size
+    }
+
+    /// Clear all elements.
+    #[inline]
+    pub fn clear(&mut self) {
+        for word in &mut self.words {
+            *word = 0;
+        }
+    }
+
+    /// Clear excess bits in the final word.
+    fn clear_excess_bits(&mut self) {
+        let num_bits_in_final_word = self.domain_size % WORD_BITS;
+        if num_bits_in_final_word > 0 {
+            let mask = (1 << num_bits_in_final_word) - 1;
+            let final_word_idx = self.words.len() - 1;
+            self.words[final_word_idx] &= mask;
+        }
+    }
+
+    /// Efficiently overwrite `self` with `other`.
+    pub fn overwrite(&mut self, other: &BitSet<T>) {
+        assert!(self.domain_size == other.domain_size);
+        self.words.clone_from_slice(&other.words);
+    }
+
+    /// Count the number of set bits in the set.
+    pub fn count(&self) -> usize {
+        self.words.iter().map(|e| e.count_ones() as usize).sum()
+    }
+
+    /// Returns `true` if `self` contains `elem`.
+    #[inline]
+    pub fn contains(&self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
+        let (word_index, mask) = word_index_and_mask(elem);
+        (self.words[word_index] & mask) != 0
+    }
+
+    /// Is `self` is a (non-strict) superset of `other`?
+    #[inline]
+    pub fn superset(&self, other: &BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        self.words.iter().zip(&other.words).all(|(a, b)| (a & b) == *b)
+    }
+
+    /// Is the set empty?
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.words.iter().all(|a| *a == 0)
+    }
+
+    /// Insert `elem`. Returns whether the set has changed.
+    #[inline]
+    pub fn insert(&mut self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
+        let (word_index, mask) = word_index_and_mask(elem);
+        let word_ref = &mut self.words[word_index];
+        let word = *word_ref;
+        let new_word = word | mask;
+        *word_ref = new_word;
+        new_word != word
+    }
+
+    /// Sets all bits to true.
+    pub fn insert_all(&mut self) {
+        for word in &mut self.words {
+            *word = !0;
+        }
+        self.clear_excess_bits();
+    }
+
+    /// Returns `true` if the set has changed.
+    #[inline]
+    pub fn remove(&mut self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
+        let (word_index, mask) = word_index_and_mask(elem);
+        let word_ref = &mut self.words[word_index];
+        let word = *word_ref;
+        let new_word = word & !mask;
+        *word_ref = new_word;
+        new_word != word
+    }
+
+    /// Sets `self = self | other` and returns `true` if `self` changed
+    /// (i.e., if new bits were added).
+    pub fn union(&mut self, other: &impl UnionIntoBitSet<T>) -> bool {
+        other.union_into(self)
+    }
+
+    /// Sets `self = self - other` and returns `true` if `self` changed.
+    /// (i.e., if any bits were removed).
+    pub fn subtract(&mut self, other: &impl SubtractFromBitSet<T>) -> bool {
+        other.subtract_from(self)
+    }
+
+    /// Sets `self = self & other` and return `true` if `self` changed.
+    /// (i.e., if any bits were removed).
+    pub fn intersect(&mut self, other: &BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        bitwise(&mut self.words, &other.words, |a, b| { a & b })
+    }
+
+    /// Gets a slice of the underlying words.
+    pub fn words(&self) -> &[Word] {
+        &self.words
+    }
+
+    /// Iterates over the indices of set bits in a sorted order.
+    #[inline]
+    pub fn iter(&self) -> BitIter<'_, T> {
+        BitIter {
+            cur: None,
+            iter: self.words.iter().enumerate(),
+            marker: PhantomData,
+        }
+    }
+
+    /// Duplicates the set as a hybrid set.
+    pub fn to_hybrid(&self) -> HybridBitSet<T> {
+        // Note: we currently don't bother trying to make a Sparse set.
+        HybridBitSet::Dense(self.to_owned())
+    }
+
+    /// Set `self = self | other`. In contrast to `union` returns `true` if the set contains at
+    /// least one bit that is not in `other` (i.e. `other` is not a superset of `self`).
+    ///
+    /// This is an optimization for union of a hybrid bitset.
+    fn reverse_union_sparse(&mut self, sparse: &SparseBitSet<T>) -> bool {
+        assert!(sparse.domain_size == self.domain_size);
+        self.clear_excess_bits();
+
+        let mut not_already = false;
+        // Index of the current word not yet merged.
+        let mut current_index = 0;
+        // Mask of bits that came from the sparse set in the current word.
+        let mut new_bit_mask = 0;
+        for (word_index, mask) in sparse.iter().map(|x| word_index_and_mask(*x)) {
+            // Next bit is in a word not inspected yet.
+            if word_index > current_index {
+                self.words[current_index] |= new_bit_mask;
+                // Were there any bits in the old word that did not occur in the sparse set?
+                not_already |= (self.words[current_index] ^ new_bit_mask) != 0;
+                // Check all words we skipped for any set bit.
+                not_already |= self.words[current_index+1..word_index].iter().any(|&x| x != 0);
+                // Update next word.
+                current_index = word_index;
+                // Reset bit mask, no bits have been merged yet.
+                new_bit_mask = 0;
+            }
+            // Add bit and mark it as coming from the sparse set.
+            // self.words[word_index] |= mask;
+            new_bit_mask |= mask;
+        }
+        self.words[current_index] |= new_bit_mask;
+        // Any bits in the last inspected word that were not in the sparse set?
+        not_already |= (self.words[current_index] ^ new_bit_mask) != 0;
+        // Any bits in the tail? Note `clear_excess_bits` before.
+        not_already |= self.words[current_index+1..].iter().any(|&x| x != 0);
+
+        not_already
+    }
+}
+
+/// This is implemented by all the bitsets so that BitSet::union() can be
+/// passed any type of bitset.
+pub trait UnionIntoBitSet<T: Idx> {
+    // Performs `other = other | self`.
+    fn union_into(&self, other: &mut BitSet<T>) -> bool;
+}
+
+/// This is implemented by all the bitsets so that BitSet::subtract() can be
+/// passed any type of bitset.
+pub trait SubtractFromBitSet<T: Idx> {
+    // Performs `other = other - self`.
+    fn subtract_from(&self, other: &mut BitSet<T>) -> bool;
+}
+
+impl<T: Idx> UnionIntoBitSet<T> for BitSet<T> {
+    fn union_into(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        bitwise(&mut other.words, &self.words, |a, b| { a | b })
+    }
+}
+
+impl<T: Idx> SubtractFromBitSet<T> for BitSet<T> {
+    fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        bitwise(&mut other.words, &self.words, |a, b| { a & !b })
+    }
+}
+
+impl<T: Idx> fmt::Debug for BitSet<T> {
+    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
+        w.debug_list()
+         .entries(self.iter())
+         .finish()
+    }
+}
+
+impl<T: Idx> ToString for BitSet<T> {
+    fn to_string(&self) -> String {
+        let mut result = String::new();
+        let mut sep = '[';
+
+        // Note: this is a little endian printout of bytes.
+
+        // i tracks how many bits we have printed so far.
+        let mut i = 0;
+        for word in &self.words {
+            let mut word = *word;
+            for _ in 0..WORD_BYTES { // for each byte in `word`:
+                let remain = self.domain_size - i;
+                // If less than a byte remains, then mask just that many bits.
+                let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
+                assert!(mask <= 0xFF);
+                let byte = word & mask;
+
+                result.push_str(&format!("{}{:02x}", sep, byte));
+
+                if remain <= 8 { break; }
+                word >>= 8;
+                i += 8;
+                sep = '-';
+            }
+            sep = '|';
+        }
+        result.push(']');
+
+        result
+    }
+}
+
+pub struct BitIter<'a, T: Idx> {
+    cur: Option<(Word, usize)>,
+    iter: iter::Enumerate<slice::Iter<'a, Word>>,
+    marker: PhantomData<T>
+}
+
+impl<'a, T: Idx> Iterator for BitIter<'a, T> {
+    type Item = T;
+    fn next(&mut self) -> Option<T> {
+        loop {
+            if let Some((ref mut word, offset)) = self.cur {
+                let bit_pos = word.trailing_zeros() as usize;
+                if bit_pos != WORD_BITS {
+                    let bit = 1 << bit_pos;
+                    *word ^= bit;
+                    return Some(T::new(bit_pos + offset))
+                }
+            }
+
+            let (i, word) = self.iter.next()?;
+            self.cur = Some((*word, WORD_BITS * i));
+        }
+    }
+}
+
+#[inline]
+fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
+    where Op: Fn(Word, Word) -> Word
+{
+    assert_eq!(out_vec.len(), in_vec.len());
+    let mut changed = false;
+    for (out_elem, in_elem) in out_vec.iter_mut().zip(in_vec.iter()) {
+        let old_val = *out_elem;
+        let new_val = op(old_val, *in_elem);
+        *out_elem = new_val;
+        changed |= old_val != new_val;
+    }
+    changed
+}
+
+const SPARSE_MAX: usize = 8;
+
+/// A fixed-size bitset type with a sparse representation and a maximum of
+/// `SPARSE_MAX` elements. The elements are stored as a sorted `SmallVec` with
+/// no duplicates; although `SmallVec` can spill its elements to the heap, that
+/// never happens within this type because of the `SPARSE_MAX` limit.
+///
+/// This type is used by `HybridBitSet`; do not use directly.
+#[derive(Clone, Debug)]
+pub struct SparseBitSet<T: Idx> {
+    domain_size: usize,
+    elems: SmallVec<[T; SPARSE_MAX]>,
+}
+
+impl<T: Idx> SparseBitSet<T> {
+    fn new_empty(domain_size: usize) -> Self {
+        SparseBitSet {
+            domain_size,
+            elems: SmallVec::new()
+        }
+    }
+
+    fn len(&self) -> usize {
+        self.elems.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.elems.len() == 0
+    }
+
+    fn contains(&self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
+        self.elems.contains(&elem)
+    }
+
+    fn insert(&mut self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
+        let changed = if let Some(i) = self.elems.iter().position(|&e| e >= elem) {
+            if self.elems[i] == elem {
+                // `elem` is already in the set.
+                false
+            } else {
+                // `elem` is smaller than one or more existing elements.
+                self.elems.insert(i, elem);
+                true
+            }
+        } else {
+            // `elem` is larger than all existing elements.
+            self.elems.push(elem);
+            true
+        };
+        assert!(self.len() <= SPARSE_MAX);
+        changed
+    }
+
+    fn remove(&mut self, elem: T) -> bool {
+        assert!(elem.index() < self.domain_size);
+        if let Some(i) = self.elems.iter().position(|&e| e == elem) {
+            self.elems.remove(i);
+            true
+        } else {
+            false
+        }
+    }
+
+    fn to_dense(&self) -> BitSet<T> {
+        let mut dense = BitSet::new_empty(self.domain_size);
+        for elem in self.elems.iter() {
+            dense.insert(*elem);
+        }
+        dense
+    }
+
+    fn iter(&self) -> slice::Iter<'_, T> {
+        self.elems.iter()
+    }
+}
+
+impl<T: Idx> UnionIntoBitSet<T> for SparseBitSet<T> {
+    fn union_into(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        let mut changed = false;
+        for elem in self.iter() {
+            changed |= other.insert(*elem);
+        }
+        changed
+    }
+}
+
+impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
+    fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        let mut changed = false;
+        for elem in self.iter() {
+            changed |= other.remove(*elem);
+        }
+        changed
+    }
+}
+
+/// A fixed-size bitset type with a hybrid representation: sparse when there
+/// are up to a `SPARSE_MAX` elements in the set, but dense when there are more
+/// than `SPARSE_MAX`.
+///
+/// This type is especially efficient for sets that typically have a small
+/// number of elements, but a large `domain_size`, and are cleared frequently.
+///
+/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
+/// just be `usize`.
+///
+/// All operations that involve an element will panic if the element is equal
+/// to or greater than the domain size. All operations that involve two bitsets
+/// will panic if the bitsets have differing domain sizes.
+#[derive(Clone, Debug)]
+pub enum HybridBitSet<T: Idx> {
+    Sparse(SparseBitSet<T>),
+    Dense(BitSet<T>),
+}
+
+impl<T: Idx> HybridBitSet<T> {
+    pub fn new_empty(domain_size: usize) -> Self {
+        HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size))
+    }
+
+    fn domain_size(&self) -> usize {
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.domain_size,
+            HybridBitSet::Dense(dense) => dense.domain_size,
+        }
+    }
+
+    pub fn clear(&mut self) {
+        let domain_size = self.domain_size();
+        *self = HybridBitSet::new_empty(domain_size);
+    }
+
+    pub fn contains(&self, elem: T) -> bool {
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.contains(elem),
+            HybridBitSet::Dense(dense) => dense.contains(elem),
+        }
+    }
+
+    pub fn superset(&self, other: &HybridBitSet<T>) -> bool {
+        match (self, other) {
+            (HybridBitSet::Dense(self_dense), HybridBitSet::Dense(other_dense)) => {
+                self_dense.superset(other_dense)
+            }
+            _ => {
+                assert!(self.domain_size() == other.domain_size());
+                other.iter().all(|elem| self.contains(elem))
+            }
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.is_empty(),
+            HybridBitSet::Dense(dense) => dense.is_empty(),
+        }
+    }
+
+    pub fn insert(&mut self, elem: T) -> bool {
+        // No need to check `elem` against `self.domain_size` here because all
+        // the match cases check it, one way or another.
+        match self {
+            HybridBitSet::Sparse(sparse) if sparse.len() < SPARSE_MAX => {
+                // The set is sparse and has space for `elem`.
+                sparse.insert(elem)
+            }
+            HybridBitSet::Sparse(sparse) if sparse.contains(elem) => {
+                // The set is sparse and does not have space for `elem`, but
+                // that doesn't matter because `elem` is already present.
+                false
+            }
+            HybridBitSet::Sparse(sparse) => {
+                // The set is sparse and full. Convert to a dense set.
+                let mut dense = sparse.to_dense();
+                let changed = dense.insert(elem);
+                assert!(changed);
+                *self = HybridBitSet::Dense(dense);
+                changed
+            }
+            HybridBitSet::Dense(dense) => dense.insert(elem),
+        }
+    }
+
+    pub fn insert_all(&mut self) {
+        let domain_size = self.domain_size();
+        match self {
+            HybridBitSet::Sparse(_) => {
+                *self = HybridBitSet::Dense(BitSet::new_filled(domain_size));
+            }
+            HybridBitSet::Dense(dense) => dense.insert_all(),
+        }
+    }
+
+    pub fn remove(&mut self, elem: T) -> bool {
+        // Note: we currently don't bother going from Dense back to Sparse.
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.remove(elem),
+            HybridBitSet::Dense(dense) => dense.remove(elem),
+        }
+    }
+
+    pub fn union(&mut self, other: &HybridBitSet<T>) -> bool {
+        match self {
+            HybridBitSet::Sparse(self_sparse) => {
+                match other {
+                    HybridBitSet::Sparse(other_sparse) => {
+                        // Both sets are sparse. Add the elements in
+                        // `other_sparse` to `self` one at a time. This
+                        // may or may not cause `self` to be densified.
+                        assert_eq!(self.domain_size(), other.domain_size());
+                        let mut changed = false;
+                        for elem in other_sparse.iter() {
+                            changed |= self.insert(*elem);
+                        }
+                        changed
+                    }
+                    HybridBitSet::Dense(other_dense) => {
+                        // `self` is sparse and `other` is dense. To
+                        // merge them, we have two available strategies:
+                        // * Densify `self` then merge other
+                        // * Clone other then integrate bits from `self`
+                        // The second strategy requires dedicated method
+                        // since the usual `union` returns the wrong
+                        // result. In the dedicated case the computation
+                        // is slightly faster if the bits of the sparse
+                        // bitset map to only few words of the dense
+                        // representation, i.e. indices are near each
+                        // other.
+                        //
+                        // Benchmarking seems to suggest that the second
+                        // option is worth it.
+                        let mut new_dense = other_dense.clone();
+                        let changed = new_dense.reverse_union_sparse(self_sparse);
+                        *self = HybridBitSet::Dense(new_dense);
+                        changed
+                    }
+                }
+            }
+
+            HybridBitSet::Dense(self_dense) => self_dense.union(other),
+        }
+    }
+
+    /// Converts to a dense set, consuming itself in the process.
+    pub fn to_dense(self) -> BitSet<T> {
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.to_dense(),
+            HybridBitSet::Dense(dense) => dense,
+        }
+    }
+
+    pub fn iter(&self) -> HybridIter<'_, T> {
+        match self {
+            HybridBitSet::Sparse(sparse) => HybridIter::Sparse(sparse.iter()),
+            HybridBitSet::Dense(dense) => HybridIter::Dense(dense.iter()),
+        }
+    }
+}
+
+impl<T: Idx> UnionIntoBitSet<T> for HybridBitSet<T> {
+    fn union_into(&self, other: &mut BitSet<T>) -> bool {
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.union_into(other),
+            HybridBitSet::Dense(dense) => dense.union_into(other),
+        }
+    }
+}
+
+impl<T: Idx> SubtractFromBitSet<T> for HybridBitSet<T> {
+    fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+        match self {
+            HybridBitSet::Sparse(sparse) => sparse.subtract_from(other),
+            HybridBitSet::Dense(dense) => dense.subtract_from(other),
+        }
+    }
+}
+
+pub enum HybridIter<'a, T: Idx> {
+    Sparse(slice::Iter<'a, T>),
+    Dense(BitIter<'a, T>),
+}
+
+impl<'a, T: Idx> Iterator for HybridIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        match self {
+            HybridIter::Sparse(sparse) => sparse.next().map(|e| *e),
+            HybridIter::Dense(dense) => dense.next(),
+        }
+    }
+}
+
+/// A resizable bitset type with a dense representation.
+///
+/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
+/// just be `usize`.
+///
+/// All operations that involve an element will panic if the element is equal
+/// to or greater than the domain size.
+#[derive(Clone, Debug, PartialEq)]
+pub struct GrowableBitSet<T: Idx> {
+    bit_set: BitSet<T>,
+}
+
+impl<T: Idx> GrowableBitSet<T> {
+    /// Ensure that the set can hold at least `min_domain_size` elements.
+    pub fn ensure(&mut self, min_domain_size: usize) {
+        if self.bit_set.domain_size < min_domain_size {
+            self.bit_set.domain_size = min_domain_size;
+        }
+
+        let min_num_words = num_words(min_domain_size);
+        if self.bit_set.words.len() < min_num_words {
+            self.bit_set.words.resize(min_num_words, 0)
+        }
+    }
+
+    pub fn new_empty() -> GrowableBitSet<T> {
+        GrowableBitSet { bit_set: BitSet::new_empty(0) }
+    }
+
+    pub fn with_capacity(capacity: usize) -> GrowableBitSet<T> {
+        GrowableBitSet { bit_set: BitSet::new_empty(capacity) }
+    }
+
+    /// Returns `true` if the set has changed.
+    #[inline]
+    pub fn insert(&mut self, elem: T) -> bool {
+        self.ensure(elem.index() + 1);
+        self.bit_set.insert(elem)
+    }
+
+    #[inline]
+    pub fn contains(&self, elem: T) -> bool {
+        let (word_index, mask) = word_index_and_mask(elem);
+        if let Some(word) = self.bit_set.words.get(word_index) {
+            (word & mask) != 0
+        } else {
+            false
+        }
+    }
+}
+
+/// A fixed-size 2D bit matrix type with a dense representation.
+///
+/// `R` and `C` are index types used to identify rows and columns respectively;
+/// typically newtyped `usize` wrappers, but they can also just be `usize`.
+///
+/// All operations that involve a row and/or column index will panic if the
+/// index exceeds the relevant bound.
+#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+pub struct BitMatrix<R: Idx, C: Idx> {
+    num_rows: usize,
+    num_columns: usize,
+    words: Vec<Word>,
+    marker: PhantomData<(R, C)>,
+}
+
+impl<R: Idx, C: Idx> BitMatrix<R, C> {
+    /// Creates a new `rows x columns` matrix, initially empty.
+    pub fn new(num_rows: usize, num_columns: usize) -> BitMatrix<R, C> {
+        // For every element, we need one bit for every other
+        // element. Round up to an even number of words.
+        let words_per_row = num_words(num_columns);
+        BitMatrix {
+            num_rows,
+            num_columns,
+            words: vec![0; num_rows * words_per_row],
+            marker: PhantomData,
+        }
+    }
+
+    /// Creates a new matrix, with `row` used as the value for every row.
+    pub fn from_row_n(row: &BitSet<C>, num_rows: usize) -> BitMatrix<R, C> {
+        let num_columns = row.domain_size();
+        let words_per_row = num_words(num_columns);
+        assert_eq!(words_per_row, row.words().len());
+        BitMatrix {
+            num_rows,
+            num_columns,
+            words: iter::repeat(row.words()).take(num_rows).flatten().cloned().collect(),
+            marker: PhantomData,
+        }
+    }
+
+    pub fn rows(&self) -> impl Iterator<Item = R> {
+        (0..self.num_rows).map(R::new)
+    }
+
+    /// The range of bits for a given row.
+    fn range(&self, row: R) -> (usize, usize) {
+        let words_per_row = num_words(self.num_columns);
+        let start = row.index() * words_per_row;
+        (start, start + words_per_row)
+    }
+
+    /// Sets the cell at `(row, column)` to true. Put another way, insert
+    /// `column` to the bitset for `row`.
+    ///
+    /// Returns `true` if this changed the matrix.
+    pub fn insert(&mut self, row: R, column: C) -> bool {
+        assert!(row.index() < self.num_rows && column.index() < self.num_columns);
+        let (start, _) = self.range(row);
+        let (word_index, mask) = word_index_and_mask(column);
+        let words = &mut self.words[..];
+        let word = words[start + word_index];
+        let new_word = word | mask;
+        words[start + word_index] = new_word;
+        word != new_word
+    }
+
+    /// Do the bits from `row` contain `column`? Put another way, is
+    /// the matrix cell at `(row, column)` true?  Put yet another way,
+    /// if the matrix represents (transitive) reachability, can
+    /// `row` reach `column`?
+    pub fn contains(&self, row: R, column: C) -> bool {
+        assert!(row.index() < self.num_rows && column.index() < self.num_columns);
+        let (start, _) = self.range(row);
+        let (word_index, mask) = word_index_and_mask(column);
+        (self.words[start + word_index] & mask) != 0
+    }
+
+    /// Returns those indices that are true in rows `a` and `b`. This
+    /// is an O(n) operation where `n` is the number of elements
+    /// (somewhat independent from the actual size of the
+    /// intersection, in particular).
+    pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> {
+        assert!(row1.index() < self.num_rows && row2.index() < self.num_rows);
+        let (row1_start, row1_end) = self.range(row1);
+        let (row2_start, row2_end) = self.range(row2);
+        let mut result = Vec::with_capacity(self.num_columns);
+        for (base, (i, j)) in (row1_start..row1_end).zip(row2_start..row2_end).enumerate() {
+            let mut v = self.words[i] & self.words[j];
+            for bit in 0..WORD_BITS {
+                if v == 0 {
+                    break;
+                }
+                if v & 0x1 != 0 {
+                    result.push(C::new(base * WORD_BITS + bit));
+                }
+                v >>= 1;
+            }
+        }
+        result
+    }
+
+    /// Adds the bits from row `read` to the bits from row `write`, and
+    /// returns `true` if anything changed.
+    ///
+    /// This is used when computing transitive reachability because if
+    /// you have an edge `write -> read`, because in that case
+    /// `write` can reach everything that `read` can (and
+    /// potentially more).
+    pub fn union_rows(&mut self, read: R, write: R) -> bool {
+        assert!(read.index() < self.num_rows && write.index() < self.num_rows);
+        let (read_start, read_end) = self.range(read);
+        let (write_start, write_end) = self.range(write);
+        let words = &mut self.words[..];
+        let mut changed = false;
+        for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) {
+            let word = words[write_index];
+            let new_word = word | words[read_index];
+            words[write_index] = new_word;
+            changed |= word != new_word;
+        }
+        changed
+    }
+
+    /// Adds the bits from `with` to the bits from row `write`, and
+    /// returns `true` if anything changed.
+    pub fn union_row_with(&mut self, with: &BitSet<C>, write: R) -> bool {
+        assert!(write.index() < self.num_rows);
+        assert_eq!(with.domain_size(), self.num_columns);
+        let (write_start, write_end) = self.range(write);
+        let mut changed = false;
+        for (read_index, write_index) in (0..with.words().len()).zip(write_start..write_end) {
+            let word = self.words[write_index];
+            let new_word = word | with.words()[read_index];
+            self.words[write_index] = new_word;
+            changed |= word != new_word;
+        }
+        changed
+    }
+
+    /// Sets every cell in `row` to true.
+    pub fn insert_all_into_row(&mut self, row: R) {
+        assert!(row.index() < self.num_rows);
+        let (start, end) = self.range(row);
+        let words = &mut self.words[..];
+        for index in start..end {
+            words[index] = !0;
+        }
+        self.clear_excess_bits(row);
+    }
+
+    /// Clear excess bits in the final word of the row.
+    fn clear_excess_bits(&mut self, row: R) {
+        let num_bits_in_final_word = self.num_columns % WORD_BITS;
+        if num_bits_in_final_word > 0 {
+            let mask = (1 << num_bits_in_final_word) - 1;
+            let (_, end) = self.range(row);
+            let final_word_idx = end - 1;
+            self.words[final_word_idx] &= mask;
+        }
+    }
+
+    /// Gets a slice of the underlying words.
+    pub fn words(&self) -> &[Word] {
+        &self.words
+    }
+
+    /// Iterates through all the columns set to true in a given row of
+    /// the matrix.
+    pub fn iter(&self, row: R) -> BitIter<'_, C> {
+        assert!(row.index() < self.num_rows);
+        let (start, end) = self.range(row);
+        BitIter {
+            cur: None,
+            iter: self.words[start..end].iter().enumerate(),
+            marker: PhantomData,
+        }
+    }
+
+    /// Returns the number of elements in `row`.
+    pub fn count(&self, row: R) -> usize {
+        let (start, end) = self.range(row);
+        self.words[start..end].iter().map(|e| e.count_ones() as usize).sum()
+    }
+}
+
+/// A fixed-column-size, variable-row-size 2D bit matrix with a moderately
+/// sparse representation.
+///
+/// Initially, every row has no explicit representation. If any bit within a
+/// row is set, the entire row is instantiated as `Some(<HybridBitSet>)`.
+/// Furthermore, any previously uninstantiated rows prior to it will be
+/// instantiated as `None`. Those prior rows may themselves become fully
+/// instantiated later on if any of their bits are set.
+///
+/// `R` and `C` are index types used to identify rows and columns respectively;
+/// typically newtyped `usize` wrappers, but they can also just be `usize`.
+#[derive(Clone, Debug)]
+pub struct SparseBitMatrix<R, C>
+where
+    R: Idx,
+    C: Idx,
+{
+    num_columns: usize,
+    rows: IndexVec<R, Option<HybridBitSet<C>>>,
+}
+
+impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
+    /// Creates a new empty sparse bit matrix with no rows or columns.
+    pub fn new(num_columns: usize) -> Self {
+        Self {
+            num_columns,
+            rows: IndexVec::new(),
+        }
+    }
+
+    fn ensure_row(&mut self, row: R) -> &mut HybridBitSet<C> {
+        // Instantiate any missing rows up to and including row `row` with an
+        // empty HybridBitSet.
+        self.rows.ensure_contains_elem(row, || None);
+
+        // Then replace row `row` with a full HybridBitSet if necessary.
+        let num_columns = self.num_columns;
+        self.rows[row].get_or_insert_with(|| HybridBitSet::new_empty(num_columns))
+    }
+
+    /// Sets the cell at `(row, column)` to true. Put another way, insert
+    /// `column` to the bitset for `row`.
+    ///
+    /// Returns `true` if this changed the matrix.
+    pub fn insert(&mut self, row: R, column: C) -> bool {
+        self.ensure_row(row).insert(column)
+    }
+
+    /// Do the bits from `row` contain `column`? Put another way, is
+    /// the matrix cell at `(row, column)` true?  Put yet another way,
+    /// if the matrix represents (transitive) reachability, can
+    /// `row` reach `column`?
+    pub fn contains(&self, row: R, column: C) -> bool {
+        self.row(row).map_or(false, |r| r.contains(column))
+    }
+
+    /// Adds the bits from row `read` to the bits from row `write`, and
+    /// returns `true` if anything changed.
+    ///
+    /// This is used when computing transitive reachability because if
+    /// you have an edge `write -> read`, because in that case
+    /// `write` can reach everything that `read` can (and
+    /// potentially more).
+    pub fn union_rows(&mut self, read: R, write: R) -> bool {
+        if read == write || self.row(read).is_none() {
+            return false;
+        }
+
+        self.ensure_row(write);
+        if let (Some(read_row), Some(write_row)) = self.rows.pick2_mut(read, write) {
+            write_row.union(read_row)
+        } else {
+            unreachable!()
+        }
+    }
+
+    /// Union a row, `from`, into the `into` row.
+    pub fn union_into_row(&mut self, into: R, from: &HybridBitSet<C>) -> bool {
+        self.ensure_row(into).union(from)
+    }
+
+    /// Insert all bits in the given row.
+    pub fn insert_all_into_row(&mut self, row: R) {
+        self.ensure_row(row).insert_all();
+    }
+
+    pub fn rows(&self) -> impl Iterator<Item = R> {
+        self.rows.indices()
+    }
+
+    /// Iterates through all the columns set to true in a given row of
+    /// the matrix.
+    pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
+        self.row(row).into_iter().flat_map(|r| r.iter())
+    }
+
+    pub fn row(&self, row: R) -> Option<&HybridBitSet<C>> {
+        if let Some(Some(row)) = self.rows.get(row) {
+            Some(row)
+        } else {
+            None
+        }
+    }
+}
+
+#[inline]
+fn num_words<T: Idx>(domain_size: T) -> usize {
+    (domain_size.index() + WORD_BITS - 1) / WORD_BITS
+}
+
+#[inline]
+fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
+    let elem = elem.index();
+    let word_index = elem / WORD_BITS;
+    let mask = 1 << (elem % WORD_BITS);
+    (word_index, mask)
+}
diff --git a/src/librustc_index/bit_set/tests.rs b/src/librustc_index/bit_set/tests.rs
new file mode 100644 (file)
index 0000000..ac79138
--- /dev/null
@@ -0,0 +1,369 @@
+use super::*;
+
+extern crate test;
+use test::Bencher;
+
+#[test]
+fn test_new_filled() {
+    for i in 0..128 {
+        let idx_buf = BitSet::new_filled(i);
+        let elems: Vec<usize> = idx_buf.iter().collect();
+        let expected: Vec<usize> = (0..i).collect();
+        assert_eq!(elems, expected);
+    }
+}
+
+#[test]
+fn bitset_iter_works() {
+    let mut bitset: BitSet<usize> = BitSet::new_empty(100);
+    bitset.insert(1);
+    bitset.insert(10);
+    bitset.insert(19);
+    bitset.insert(62);
+    bitset.insert(63);
+    bitset.insert(64);
+    bitset.insert(65);
+    bitset.insert(66);
+    bitset.insert(99);
+    assert_eq!(
+        bitset.iter().collect::<Vec<_>>(),
+        [1, 10, 19, 62, 63, 64, 65, 66, 99]
+    );
+}
+
+#[test]
+fn bitset_iter_works_2() {
+    let mut bitset: BitSet<usize> = BitSet::new_empty(320);
+    bitset.insert(0);
+    bitset.insert(127);
+    bitset.insert(191);
+    bitset.insert(255);
+    bitset.insert(319);
+    assert_eq!(bitset.iter().collect::<Vec<_>>(), [0, 127, 191, 255, 319]);
+}
+
+#[test]
+fn union_two_sets() {
+    let mut set1: BitSet<usize> = BitSet::new_empty(65);
+    let mut set2: BitSet<usize> = BitSet::new_empty(65);
+    assert!(set1.insert(3));
+    assert!(!set1.insert(3));
+    assert!(set2.insert(5));
+    assert!(set2.insert(64));
+    assert!(set1.union(&set2));
+    assert!(!set1.union(&set2));
+    assert!(set1.contains(3));
+    assert!(!set1.contains(4));
+    assert!(set1.contains(5));
+    assert!(!set1.contains(63));
+    assert!(set1.contains(64));
+}
+
+#[test]
+fn hybrid_bitset() {
+    let mut sparse038: HybridBitSet<usize> = HybridBitSet::new_empty(256);
+    assert!(sparse038.is_empty());
+    assert!(sparse038.insert(0));
+    assert!(sparse038.insert(1));
+    assert!(sparse038.insert(8));
+    assert!(sparse038.insert(3));
+    assert!(!sparse038.insert(3));
+    assert!(sparse038.remove(1));
+    assert!(!sparse038.is_empty());
+    assert_eq!(sparse038.iter().collect::<Vec<_>>(), [0, 3, 8]);
+
+    for i in 0..256 {
+        if i == 0 || i == 3 || i == 8 {
+            assert!(sparse038.contains(i));
+        } else {
+            assert!(!sparse038.contains(i));
+        }
+    }
+
+    let mut sparse01358 = sparse038.clone();
+    assert!(sparse01358.insert(1));
+    assert!(sparse01358.insert(5));
+    assert_eq!(sparse01358.iter().collect::<Vec<_>>(), [0, 1, 3, 5, 8]);
+
+    let mut dense10 = HybridBitSet::new_empty(256);
+    for i in 0..10 {
+        assert!(dense10.insert(i));
+    }
+    assert!(!dense10.is_empty());
+    assert_eq!(dense10.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+    let mut dense256 = HybridBitSet::new_empty(256);
+    assert!(dense256.is_empty());
+    dense256.insert_all();
+    assert!(!dense256.is_empty());
+    for i in 0..256 {
+        assert!(dense256.contains(i));
+    }
+
+    assert!(sparse038.superset(&sparse038));    // sparse + sparse (self)
+    assert!(sparse01358.superset(&sparse038));  // sparse + sparse
+    assert!(dense10.superset(&sparse038));      // dense + sparse
+    assert!(dense10.superset(&dense10));        // dense + dense (self)
+    assert!(dense256.superset(&dense10));       // dense + dense
+
+    let mut hybrid = sparse038;
+    assert!(!sparse01358.union(&hybrid));       // no change
+    assert!(hybrid.union(&sparse01358));
+    assert!(hybrid.superset(&sparse01358) && sparse01358.superset(&hybrid));
+    assert!(!dense10.union(&sparse01358));
+    assert!(!dense256.union(&dense10));
+    let mut dense = dense10;
+    assert!(dense.union(&dense256));
+    assert!(dense.superset(&dense256) && dense256.superset(&dense));
+    assert!(hybrid.union(&dense256));
+    assert!(hybrid.superset(&dense256) && dense256.superset(&hybrid));
+
+    assert_eq!(dense256.iter().count(), 256);
+    let mut dense0 = dense256;
+    for i in 0..256 {
+        assert!(dense0.remove(i));
+    }
+    assert!(!dense0.remove(0));
+    assert!(dense0.is_empty());
+}
+
+#[test]
+fn grow() {
+    let mut set: GrowableBitSet<usize> = GrowableBitSet::with_capacity(65);
+    for index in 0..65 {
+        assert!(set.insert(index));
+        assert!(!set.insert(index));
+    }
+    set.ensure(128);
+
+    // Check if the bits set before growing are still set
+    for index in 0..65 {
+        assert!(set.contains(index));
+    }
+
+    // Check if the new bits are all un-set
+    for index in 65..128 {
+        assert!(!set.contains(index));
+    }
+
+    // Check that we can set all new bits without running out of bounds
+    for index in 65..128 {
+        assert!(set.insert(index));
+        assert!(!set.insert(index));
+    }
+}
+
+#[test]
+fn matrix_intersection() {
+    let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(200, 200);
+
+    // (*) Elements reachable from both 2 and 65.
+
+    matrix.insert(2, 3);
+    matrix.insert(2, 6);
+    matrix.insert(2, 10); // (*)
+    matrix.insert(2, 64); // (*)
+    matrix.insert(2, 65);
+    matrix.insert(2, 130);
+    matrix.insert(2, 160); // (*)
+
+    matrix.insert(64, 133);
+
+    matrix.insert(65, 2);
+    matrix.insert(65, 8);
+    matrix.insert(65, 10); // (*)
+    matrix.insert(65, 64); // (*)
+    matrix.insert(65, 68);
+    matrix.insert(65, 133);
+    matrix.insert(65, 160); // (*)
+
+    let intersection = matrix.intersect_rows(2, 64);
+    assert!(intersection.is_empty());
+
+    let intersection = matrix.intersect_rows(2, 65);
+    assert_eq!(intersection, &[10, 64, 160]);
+}
+
+#[test]
+fn matrix_iter() {
+    let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(64, 100);
+    matrix.insert(3, 22);
+    matrix.insert(3, 75);
+    matrix.insert(2, 99);
+    matrix.insert(4, 0);
+    matrix.union_rows(3, 5);
+    matrix.insert_all_into_row(6);
+
+    let expected = [99];
+    let mut iter = expected.iter();
+    for i in matrix.iter(2) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    assert_eq!(matrix.count(3), expected.len());
+    for i in matrix.iter(3) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [0];
+    let mut iter = expected.iter();
+    assert_eq!(matrix.count(4), expected.len());
+    for i in matrix.iter(4) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    assert_eq!(matrix.count(5), expected.len());
+    for i in matrix.iter(5) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    assert_eq!(matrix.count(6), 100);
+    let mut count = 0;
+    for (idx, i) in matrix.iter(6).enumerate() {
+        assert_eq!(idx, i);
+        count += 1;
+    }
+    assert_eq!(count, 100);
+
+    if let Some(i) = matrix.iter(7).next() {
+        panic!("expected no elements in row, but contains element {:?}", i);
+    }
+}
+
+#[test]
+fn sparse_matrix_iter() {
+    let mut matrix: SparseBitMatrix<usize, usize> = SparseBitMatrix::new(100);
+    matrix.insert(3, 22);
+    matrix.insert(3, 75);
+    matrix.insert(2, 99);
+    matrix.insert(4, 0);
+    matrix.union_rows(3, 5);
+
+    let expected = [99];
+    let mut iter = expected.iter();
+    for i in matrix.iter(2) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    for i in matrix.iter(3) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [0];
+    let mut iter = expected.iter();
+    for i in matrix.iter(4) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    for i in matrix.iter(5) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+}
+
+/// Merge dense hybrid set into empty sparse hybrid set.
+#[bench]
+fn union_hybrid_sparse_empty_to_dense(b: &mut Bencher) {
+    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(256);
+    for i in 0..10 {
+        assert!(pre_dense.insert(i));
+    }
+    let pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(256);
+    b.iter(|| {
+        let dense = pre_dense.clone();
+        let mut sparse = pre_sparse.clone();
+        sparse.union(&dense);
+    })
+}
+
+/// Merge dense hybrid set into full hybrid set with same indices.
+#[bench]
+fn union_hybrid_sparse_full_to_dense(b: &mut Bencher) {
+    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(256);
+    for i in 0..10 {
+        assert!(pre_dense.insert(i));
+    }
+    let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(256);
+    for i in 0..SPARSE_MAX {
+        assert!(pre_sparse.insert(i));
+    }
+    b.iter(|| {
+        let dense = pre_dense.clone();
+        let mut sparse = pre_sparse.clone();
+        sparse.union(&dense);
+    })
+}
+
+/// Merge dense hybrid set into full hybrid set with indices over the whole domain.
+#[bench]
+fn union_hybrid_sparse_domain_to_dense(b: &mut Bencher) {
+    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX*64);
+    for i in 0..10 {
+        assert!(pre_dense.insert(i));
+    }
+    let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX*64);
+    for i in 0..SPARSE_MAX {
+        assert!(pre_sparse.insert(i*64));
+    }
+    b.iter(|| {
+        let dense = pre_dense.clone();
+        let mut sparse = pre_sparse.clone();
+        sparse.union(&dense);
+    })
+}
+
+/// Merge dense hybrid set into empty hybrid set where the domain is very small.
+#[bench]
+fn union_hybrid_sparse_empty_small_domain(b: &mut Bencher) {
+    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
+    for i in 0..SPARSE_MAX {
+        assert!(pre_dense.insert(i));
+    }
+    let pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
+    b.iter(|| {
+        let dense = pre_dense.clone();
+        let mut sparse = pre_sparse.clone();
+        sparse.union(&dense);
+    })
+}
+
+/// Merge dense hybrid set into full hybrid set where the domain is very small.
+#[bench]
+fn union_hybrid_sparse_full_small_domain(b: &mut Bencher) {
+    let mut pre_dense: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
+    for i in 0..SPARSE_MAX {
+        assert!(pre_dense.insert(i));
+    }
+    let mut pre_sparse: HybridBitSet<usize> = HybridBitSet::new_empty(SPARSE_MAX);
+    for i in 0..SPARSE_MAX {
+        assert!(pre_sparse.insert(i));
+    }
+    b.iter(|| {
+        let dense = pre_dense.clone();
+        let mut sparse = pre_sparse.clone();
+        sparse.union(&dense);
+    })
+}
diff --git a/src/librustc_index/lib.rs b/src/librustc_index/lib.rs
new file mode 100644 (file)
index 0000000..ad242df
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(allow_internal_unstable)]
+#![feature(unboxed_closures)]
+#![feature(test)]
+#![feature(fn_traits)]
+
+pub mod vec;
+pub mod bit_set;
diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs
new file mode 100644 (file)
index 0000000..6e80b48
--- /dev/null
@@ -0,0 +1,830 @@
+use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
+
+use std::fmt::Debug;
+use std::iter::{self, FromIterator};
+use std::slice;
+use std::marker::PhantomData;
+use std::ops::{Index, IndexMut, Range, RangeBounds};
+use std::fmt;
+use std::hash::Hash;
+use std::vec;
+use std::u32;
+
+/// Represents some newtyped `usize` wrapper.
+///
+/// Purpose: avoid mixing indexes for different bitvector domains.
+pub trait Idx: Copy + 'static + Ord + Debug + Hash {
+    fn new(idx: usize) -> Self;
+
+    fn index(self) -> usize;
+
+    fn increment_by(&mut self, amount: usize) {
+        *self = self.plus(amount);
+    }
+
+    fn plus(self, amount: usize) -> Self {
+        Self::new(self.index() + amount)
+    }
+}
+
+impl Idx for usize {
+    #[inline]
+    fn new(idx: usize) -> Self { idx }
+    #[inline]
+    fn index(self) -> usize { self }
+}
+
+impl Idx for u32 {
+    #[inline]
+    fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 }
+    #[inline]
+    fn index(self) -> usize { self as usize }
+}
+
+/// Creates a struct type `S` that can be used as an index with
+/// `IndexVec` and so on.
+///
+/// There are two ways of interacting with these indices:
+///
+/// - The `From` impls are the preferred way. So you can do
+///   `S::from(v)` with a `usize` or `u32`. And you can convert back
+///   to an integer with `u32::from(s)`.
+///
+/// - Alternatively, you can use the methods `S::new(v)` and `s.index()`
+///   to create/return a value.
+///
+/// Internally, the index uses a u32, so the index must not exceed
+/// `u32::MAX`. You can also customize things like the `Debug` impl,
+/// what traits are derived, and so forth via the macro.
+#[macro_export]
+#[allow_internal_unstable(step_trait, rustc_attrs)]
+macro_rules! newtype_index {
+    // ---- public rules ----
+
+    // Use default constants
+    ($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => (
+        $crate::newtype_index!(
+            // Leave out derives marker so we can use its absence to ensure it comes first
+            @attrs        [$(#[$attrs])*]
+            @type         [$name]
+            // shave off 256 indices at the end to allow space for packing these indices into enums
+            @max          [0xFFFF_FF00]
+            @vis          [$v]
+            @debug_format ["{}"]);
+    );
+
+    // Define any constants
+    ($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => (
+        $crate::newtype_index!(
+            // Leave out derives marker so we can use its absence to ensure it comes first
+            @attrs        [$(#[$attrs])*]
+            @type         [$name]
+            // shave off 256 indices at the end to allow space for packing these indices into enums
+            @max          [0xFFFF_FF00]
+            @vis          [$v]
+            @debug_format ["{}"]
+                          $($tokens)+);
+    );
+
+    // ---- private rules ----
+
+    // Base case, user-defined constants (if any) have already been defined
+    (@derives      [$($derives:ident,)*]
+     @attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]) => (
+        $(#[$attrs])*
+        #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
+        #[rustc_layout_scalar_valid_range_end($max)]
+        $v struct $type {
+            private: u32
+        }
+
+        impl Clone for $type {
+            fn clone(&self) -> Self {
+                *self
+            }
+        }
+
+        impl $type {
+            $v const MAX_AS_U32: u32 = $max;
+
+            $v const MAX: $type = $type::from_u32_const($max);
+
+            #[inline]
+            $v fn from_usize(value: usize) -> Self {
+                assert!(value <= ($max as usize));
+                unsafe {
+                    $type::from_u32_unchecked(value as u32)
+                }
+            }
+
+            #[inline]
+            $v fn from_u32(value: u32) -> Self {
+                assert!(value <= $max);
+                unsafe {
+                    $type::from_u32_unchecked(value)
+                }
+            }
+
+            /// Hacky variant of `from_u32` for use in constants.
+            /// This version checks the "max" constraint by using an
+            /// invalid array dereference.
+            #[inline]
+            $v const fn from_u32_const(value: u32) -> Self {
+                // This will fail at const eval time unless `value <=
+                // max` is true (in which case we get the index 0).
+                // It will also fail at runtime, of course, but in a
+                // kind of wacky way.
+                let _ = ["out of range value used"][
+                    !(value <= $max) as usize
+                ];
+
+                unsafe {
+                    $type { private: value }
+                }
+            }
+
+            #[inline]
+            $v const unsafe fn from_u32_unchecked(value: u32) -> Self {
+                $type { private: value }
+            }
+
+            /// Extracts the value of this index as an integer.
+            #[inline]
+            $v fn index(self) -> usize {
+                self.as_usize()
+            }
+
+            /// Extracts the value of this index as a `u32`.
+            #[inline]
+            $v fn as_u32(self) -> u32 {
+                self.private
+            }
+
+            /// Extracts the value of this index as a `usize`.
+            #[inline]
+            $v fn as_usize(self) -> usize {
+                self.as_u32() as usize
+            }
+        }
+
+        impl std::ops::Add<usize> for $type {
+            type Output = Self;
+
+            fn add(self, other: usize) -> Self {
+                Self::new(self.index() + other)
+            }
+        }
+
+        impl Idx for $type {
+            #[inline]
+            fn new(value: usize) -> Self {
+                Self::from(value)
+            }
+
+            #[inline]
+            fn index(self) -> usize {
+                usize::from(self)
+            }
+        }
+
+        impl ::std::iter::Step for $type {
+            #[inline]
+            fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                <usize as ::std::iter::Step>::steps_between(
+                    &Idx::index(*start),
+                    &Idx::index(*end),
+                )
+            }
+
+            #[inline]
+            fn replace_one(&mut self) -> Self {
+                ::std::mem::replace(self, Self::new(1))
+            }
+
+            #[inline]
+            fn replace_zero(&mut self) -> Self {
+                ::std::mem::replace(self, Self::new(0))
+            }
+
+            #[inline]
+            fn add_one(&self) -> Self {
+                Self::new(Idx::index(*self) + 1)
+            }
+
+            #[inline]
+            fn sub_one(&self) -> Self {
+                Self::new(Idx::index(*self) - 1)
+            }
+
+            #[inline]
+            fn add_usize(&self, u: usize) -> Option<Self> {
+                Idx::index(*self).checked_add(u).map(Self::new)
+            }
+
+            #[inline]
+            fn sub_usize(&self, u: usize) -> Option<Self> {
+                Idx::index(*self).checked_sub(u).map(Self::new)
+            }
+        }
+
+        impl From<$type> for u32 {
+            #[inline]
+            fn from(v: $type) -> u32 {
+                v.as_u32()
+            }
+        }
+
+        impl From<$type> for usize {
+            #[inline]
+            fn from(v: $type) -> usize {
+                v.as_usize()
+            }
+        }
+
+        impl From<usize> for $type {
+            #[inline]
+            fn from(value: usize) -> Self {
+                $type::from_usize(value)
+            }
+        }
+
+        impl From<u32> for $type {
+            #[inline]
+            fn from(value: u32) -> Self {
+                $type::from_u32(value)
+            }
+        }
+
+        $crate::newtype_index!(
+            @handle_debug
+            @derives      [$($derives,)*]
+            @type         [$type]
+            @debug_format [$debug_format]);
+    );
+
+    // base case for handle_debug where format is custom. No Debug implementation is emitted.
+    (@handle_debug
+     @derives      [$($_derives:ident,)*]
+     @type         [$type:ident]
+     @debug_format [custom]) => ();
+
+    // base case for handle_debug, no debug overrides found, so use default
+    (@handle_debug
+     @derives      []
+     @type         [$type:ident]
+     @debug_format [$debug_format:tt]) => (
+        impl ::std::fmt::Debug for $type {
+            fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+                write!(fmt, $debug_format, self.as_u32())
+            }
+        }
+    );
+
+    // Debug is requested for derive, don't generate any Debug implementation.
+    (@handle_debug
+     @derives      [Debug, $($derives:ident,)*]
+     @type         [$type:ident]
+     @debug_format [$debug_format:tt]) => ();
+
+    // It's not Debug, so just pop it off the front of the derives stack and check the rest.
+    (@handle_debug
+     @derives      [$_derive:ident, $($derives:ident,)*]
+     @type         [$type:ident]
+     @debug_format [$debug_format:tt]) => (
+        $crate::newtype_index!(
+            @handle_debug
+            @derives      [$($derives,)*]
+            @type         [$type]
+            @debug_format [$debug_format]);
+    );
+
+    // Append comma to end of derives list if it's missing
+    (@attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   derive [$($derives:ident),*]
+                   $($tokens:tt)*) => (
+        $crate::newtype_index!(
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          derive [$($derives,)*]
+                          $($tokens)*);
+    );
+
+    // By not including the @derives marker in this list nor in the default args, we can force it
+    // to come first if it exists. When encodable is custom, just use the derives list as-is.
+    (@attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   derive [$($derives:ident,)+]
+                   ENCODABLE = custom
+                   $($tokens:tt)*) => (
+        $crate::newtype_index!(
+            @attrs        [$(#[$attrs])*]
+            @derives      [$($derives,)+]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $($tokens)*);
+    );
+
+    // By not including the @derives marker in this list nor in the default args, we can force it
+    // to come first if it exists. When encodable isn't custom, add serialization traits by default.
+    (@attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   derive [$($derives:ident,)+]
+                   $($tokens:tt)*) => (
+        $crate::newtype_index!(
+            @derives      [$($derives,)+ RustcEncodable,]
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $($tokens)*);
+        $crate::newtype_index!(@decodable $type);
+    );
+
+    // The case where no derives are added, but encodable is overridden. Don't
+    // derive serialization traits
+    (@attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   ENCODABLE = custom
+                   $($tokens:tt)*) => (
+        $crate::newtype_index!(
+            @derives      []
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $($tokens)*);
+    );
+
+    // The case where no derives are added, add serialization derives by default
+    (@attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   $($tokens:tt)*) => (
+        $crate::newtype_index!(
+            @derives      [RustcEncodable,]
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $($tokens)*);
+        $crate::newtype_index!(@decodable $type);
+    );
+
+    (@decodable $type:ident) => (
+        impl ::rustc_serialize::Decodable for $type {
+            fn decode<D: ::rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+                d.read_u32().map(Self::from)
+            }
+        }
+    );
+
+    // Rewrite final without comma to one that includes comma
+    (@derives      [$($derives:ident,)*]
+     @attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   $name:ident = $constant:expr) => (
+        $crate::newtype_index!(
+            @derives      [$($derives,)*]
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $name = $constant,);
+    );
+
+    // Rewrite final const without comma to one that includes comma
+    (@derives      [$($derives:ident,)*]
+     @attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   $(#[doc = $doc:expr])*
+                   const $name:ident = $constant:expr) => (
+        $crate::newtype_index!(
+            @derives      [$($derives,)*]
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $(#[doc = $doc])* const $name = $constant,);
+    );
+
+    // Replace existing default for max
+    (@derives      [$($derives:ident,)*]
+     @attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$_max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   MAX = $max:expr,
+                   $($tokens:tt)*) => (
+        $crate::newtype_index!(
+            @derives      [$($derives,)*]
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $($tokens)*);
+    );
+
+    // Replace existing default for debug_format
+    (@derives      [$($derives:ident,)*]
+     @attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$_debug_format:tt]
+                   DEBUG_FORMAT = $debug_format:tt,
+                   $($tokens:tt)*) => (
+        $crate::newtype_index!(
+            @derives      [$($derives,)*]
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $($tokens)*);
+    );
+
+    // Assign a user-defined constant
+    (@derives      [$($derives:ident,)*]
+     @attrs        [$(#[$attrs:meta])*]
+     @type         [$type:ident]
+     @max          [$max:expr]
+     @vis          [$v:vis]
+     @debug_format [$debug_format:tt]
+                   $(#[doc = $doc:expr])*
+                   const $name:ident = $constant:expr,
+                   $($tokens:tt)*) => (
+        $(#[doc = $doc])*
+        pub const $name: $type = $type::from_u32_const($constant);
+        $crate::newtype_index!(
+            @derives      [$($derives,)*]
+            @attrs        [$(#[$attrs])*]
+            @type         [$type]
+            @max          [$max]
+            @vis          [$v]
+            @debug_format [$debug_format]
+                          $($tokens)*);
+    );
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct IndexVec<I: Idx, T> {
+    pub raw: Vec<T>,
+    _marker: PhantomData<fn(&I)>
+}
+
+// Whether `IndexVec` is `Send` depends only on the data,
+// not the phantom data.
+unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {}
+
+impl<I: Idx, T: Encodable> Encodable for IndexVec<I, T> {
+    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        Encodable::encode(&self.raw, s)
+    }
+}
+
+impl<I: Idx, T: Decodable> Decodable for IndexVec<I, T> {
+    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
+        Decodable::decode(d).map(|v| {
+            IndexVec { raw: v, _marker: PhantomData }
+        })
+    }
+}
+
+impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&self.raw, fmt)
+    }
+}
+
+pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
+
+impl<I: Idx, T> IndexVec<I, T> {
+    #[inline]
+    pub fn new() -> Self {
+        IndexVec { raw: Vec::new(), _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn from_raw(raw: Vec<T>) -> Self {
+        IndexVec { raw, _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Self {
+        IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn from_elem<S>(elem: T, universe: &IndexVec<I, S>) -> Self
+        where T: Clone
+    {
+        IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn from_elem_n(elem: T, n: usize) -> Self
+        where T: Clone
+    {
+        IndexVec { raw: vec![elem; n], _marker: PhantomData }
+    }
+
+    #[inline]
+    pub fn push(&mut self, d: T) -> I {
+        let idx = I::new(self.len());
+        self.raw.push(d);
+        idx
+    }
+
+    #[inline]
+    pub fn pop(&mut self) -> Option<T> {
+        self.raw.pop()
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.raw.len()
+    }
+
+    /// Gives the next index that will be assigned when `push` is
+    /// called.
+    #[inline]
+    pub fn next_index(&self) -> I {
+        I::new(self.len())
+    }
+
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.raw.is_empty()
+    }
+
+    #[inline]
+    pub fn into_iter(self) -> vec::IntoIter<T> {
+        self.raw.into_iter()
+    }
+
+    #[inline]
+    pub fn into_iter_enumerated(self) -> Enumerated<I, vec::IntoIter<T>>
+    {
+        self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn iter(&self) -> slice::Iter<'_, T> {
+        self.raw.iter()
+    }
+
+    #[inline]
+    pub fn iter_enumerated(&self) -> Enumerated<I, slice::Iter<'_, T>>
+    {
+        self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn indices(&self) -> iter::Map<Range<usize>, IntoIdx<I>> {
+        (0..self.len()).map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
+        self.raw.iter_mut()
+    }
+
+    #[inline]
+    pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<'_, T>>
+    {
+        self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn drain<'a, R: RangeBounds<usize>>(
+        &'a mut self, range: R) -> impl Iterator<Item=T> + 'a {
+        self.raw.drain(range)
+    }
+
+    #[inline]
+    pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
+        &'a mut self, range: R) -> impl Iterator<Item=(I, T)> + 'a {
+        self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData })
+    }
+
+    #[inline]
+    pub fn last(&self) -> Option<I> {
+        self.len().checked_sub(1).map(I::new)
+    }
+
+    #[inline]
+    pub fn shrink_to_fit(&mut self) {
+        self.raw.shrink_to_fit()
+    }
+
+    #[inline]
+    pub fn swap(&mut self, a: I, b: I) {
+        self.raw.swap(a.index(), b.index())
+    }
+
+    #[inline]
+    pub fn truncate(&mut self, a: usize) {
+        self.raw.truncate(a)
+    }
+
+    #[inline]
+    pub fn get(&self, index: I) -> Option<&T> {
+        self.raw.get(index.index())
+    }
+
+    #[inline]
+    pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
+        self.raw.get_mut(index.index())
+    }
+
+    /// Returns mutable references to two distinct elements, a and b. Panics if a == b.
+    #[inline]
+    pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
+        let (ai, bi) = (a.index(), b.index());
+        assert!(ai != bi);
+
+        if ai < bi {
+            let (c1, c2) = self.raw.split_at_mut(bi);
+            (&mut c1[ai], &mut c2[0])
+        } else {
+            let (c2, c1) = self.pick2_mut(b, a);
+            (c1, c2)
+        }
+    }
+
+    pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
+        IndexVec {
+            raw: self.raw,
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl<I: Idx, T: Clone> IndexVec<I, T> {
+    /// Grows the index vector so that it contains an entry for
+    /// `elem`; if that is already true, then has no
+    /// effect. Otherwise, inserts new values as needed by invoking
+    /// `fill_value`.
+    #[inline]
+    pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+        let min_new_len = elem.index() + 1;
+        if self.len() < min_new_len {
+            self.raw.resize_with(min_new_len, fill_value);
+        }
+    }
+
+    #[inline]
+    pub fn resize(&mut self, new_len: usize, value: T) {
+        self.raw.resize(new_len, value)
+    }
+
+    #[inline]
+    pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+        let min_new_len = elem.index() + 1;
+        self.raw.resize_with(min_new_len, fill_value);
+    }
+}
+
+impl<I: Idx, T: Ord> IndexVec<I, T> {
+    #[inline]
+    pub fn binary_search(&self, value: &T) -> Result<I, I> {
+        match self.raw.binary_search(value) {
+            Ok(i) => Ok(Idx::new(i)),
+            Err(i) => Err(Idx::new(i)),
+        }
+    }
+}
+
+impl<I: Idx, T> Index<I> for IndexVec<I, T> {
+    type Output = T;
+
+    #[inline]
+    fn index(&self, index: I) -> &T {
+        &self.raw[index.index()]
+    }
+}
+
+impl<I: Idx, T> IndexMut<I> for IndexVec<I, T> {
+    #[inline]
+    fn index_mut(&mut self, index: I) -> &mut T {
+        &mut self.raw[index.index()]
+    }
+}
+
+impl<I: Idx, T> Default for IndexVec<I, T> {
+    #[inline]
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<I: Idx, T> Extend<T> for IndexVec<I, T> {
+    #[inline]
+    fn extend<J: IntoIterator<Item = T>>(&mut self, iter: J) {
+        self.raw.extend(iter);
+    }
+}
+
+impl<I: Idx, T> FromIterator<T> for IndexVec<I, T> {
+    #[inline]
+    fn from_iter<J>(iter: J) -> Self where J: IntoIterator<Item=T> {
+        IndexVec { raw: FromIterator::from_iter(iter), _marker: PhantomData }
+    }
+}
+
+impl<I: Idx, T> IntoIterator for IndexVec<I, T> {
+    type Item = T;
+    type IntoIter = vec::IntoIter<T>;
+
+    #[inline]
+    fn into_iter(self) -> vec::IntoIter<T> {
+        self.raw.into_iter()
+    }
+
+}
+
+impl<'a, I: Idx, T> IntoIterator for &'a IndexVec<I, T> {
+    type Item = &'a T;
+    type IntoIter = slice::Iter<'a, T>;
+
+    #[inline]
+    fn into_iter(self) -> slice::Iter<'a, T> {
+        self.raw.iter()
+    }
+}
+
+impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> {
+    type Item = &'a mut T;
+    type IntoIter = slice::IterMut<'a, T>;
+
+    #[inline]
+    fn into_iter(self) -> slice::IterMut<'a, T> {
+        self.raw.iter_mut()
+    }
+}
+
+pub struct IntoIdx<I: Idx> { _marker: PhantomData<fn(&I)> }
+impl<I: Idx, T> FnOnce<((usize, T),)> for IntoIdx<I> {
+    type Output = (I, T);
+
+    extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output {
+        (I::new(n), t)
+    }
+}
+
+impl<I: Idx, T> FnMut<((usize, T),)> for IntoIdx<I> {
+    extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output {
+        (I::new(n), t)
+    }
+}
+
+impl<I: Idx> FnOnce<(usize,)> for IntoIdx<I> {
+    type Output = I;
+
+    extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output {
+        I::new(n)
+    }
+}
+
+impl<I: Idx> FnMut<(usize,)> for IntoIdx<I> {
+    extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output {
+        I::new(n)
+    }
+}
index 52d95a04c9a296288c5140329a1eab6c0e78224d..8474bae5a71d207f8531b165fc13ba936eb8c2ad 100644 (file)
@@ -440,6 +440,9 @@ fn configure_and_expand_inner<'a>(
             &mut krate,
             sess.diagnostic(),
             &sess.features_untracked(),
+            sess.panic_strategy(),
+            sess.target.target.options.panic_strategy,
+            sess.opts.debugging_opts.panic_abort_tests,
         )
     });
 
index 041d0aaead913724cda5ab81edd5f145a7582b36..a61a314d5492d70af1a88178355769cf74a3e6fc 100644 (file)
@@ -15,3 +15,4 @@ rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_index = { path = "../librustc_index" }
index 150719c1dbc0e7e7c11332c91f02c54ff759cc15..3d14a78c33f7ea74975e877b3862d3f1f417747b 100644 (file)
@@ -7,7 +7,7 @@
 use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
 use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx, SizeSkeleton};
 use rustc::{lint, util};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use util::nodemap::FxHashSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
index 3d3a020ef0c8e71b60ea893c07bcf0819e09af6d..0540c95d3ded382b1192e67965f3d2ef56ea524c 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(proc_macro_hygiene)]
 #![allow(rustc::default_hash_types)]
 
 #![recursion_limit="128"]
index 5ff60a9267bad52ba8dbde98a128679ceace9f42..032470e1400abbb42455be173960d7f251b236e8 100644 (file)
@@ -18,6 +18,7 @@ rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_target = { path = "../librustc_target" }
+rustc_index = { path = "../librustc_index" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 stable_deref_trait = "1.0.0"
 syntax = { path = "../libsyntax" }
index 5bf4067431f24a6b73a8e08ee4c2df3895377021..d3619b2f5de90beda0f7b572a69384d69ea27016 100644 (file)
@@ -6,7 +6,7 @@
 use rustc::hir::map::definitions::DefPathTable;
 use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
 use rustc::mir::interpret::AllocDecodingState;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc::util::nodemap::{FxHashMap, NodeMap};
 
 use rustc_data_structures::sync::{Lrc, RwLock, Lock};
index 83182df31cf528bb2a4758eecd56357fe743365e..edb6f594fdd0d98fecdbed4425d449f61fd0c9d5 100644 (file)
@@ -35,7 +35,7 @@
 use syntax::parse::parser::emit_unclosed_delims;
 use syntax::symbol::Symbol;
 use syntax_pos::{Span, FileName};
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 
 macro_rules! provide {
     (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
index 3c6a1c4744696305da2b9e408c7bd41a3f2dd138..9fcc3101545995fd57fe6b0091d26fcd5e499247 100644 (file)
@@ -3,7 +3,7 @@
 use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
 use crate::schema::*;
 
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::sync::{Lrc, ReadGuard};
 use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc::hir;
index 9beeacbe72d80199e5ad0ca202102b465f3f0413..a86bc283cedc6d05eba5b2c27d9a124de1fb6729 100644 (file)
@@ -8,7 +8,7 @@
 use rustc::hir::GenericParamKind;
 use rustc::hir::map::definitions::DefPathTable;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc::middle::dependency_format::Linkage;
 use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel,
                                       metadata_symbol_name};
index 4be70c62035697a93c4ed65df9db1c38d6059ad2..2069adea021b8d841cd9c1af1fbedb2758f6ef0c 100644 (file)
@@ -11,7 +11,7 @@
 use rustc::session::config::SymbolManglingVersion;
 use rustc::ty::{self, Ty, ReprOptions};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::svh::Svh;
 
 use syntax::{ast, attr};
index f296753a0304cfd125d7044885284f058f1f760d..f0cdcf2136bfa7d8945c6e7acc467761db5bdecd 100644 (file)
@@ -19,6 +19,7 @@ polonius-engine  = "0.10.0"
 rustc = { path = "../librustc" }
 rustc_target = { path = "../librustc_target" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_index = { path = "../librustc_index" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
index db19cbc3175f8c60be5c0edbcdd637525134cc49..7dd1db3b7bdbc342ae50737fd5cf05040df731db 100644 (file)
@@ -8,8 +8,8 @@
 use rustc::mir::{self, Location, Body, Local};
 use rustc::ty::{RegionVid, TyCtxt};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_index::bit_set::BitSet;
 use std::fmt;
 use std::ops::Index;
 
index 7d5d58ed284685385936a8f0f85995f75bb7e4fb..ef459ef0c1b702c6692317b39dbb7a5ee5fcb8c0 100644 (file)
@@ -7,7 +7,7 @@
 };
 use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use syntax_pos::Span;
 use syntax::source_map::DesugaringKind;
index 1f17ab69f6660b722e613a46586df945aeb9a044..ce5d2a14bd122380711d2b23664750ac5ffa9258 100644 (file)
@@ -5,7 +5,7 @@
 
 use rustc::mir::{BasicBlock, Local, Location};
 use rustc::ty::RegionVid;
-use rustc_data_structures::bit_set::BitIter;
+use rustc_index::bit_set::BitIter;
 
 use crate::borrow_check::location::LocationIndex;
 
index cc44dc3f5d46bd34be686d7bcea9a36281710d7e..9e94317b87e5493789b563d5d9ad9dd0ffa0a85c 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::mir::{BasicBlock, Location, Body};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 
 /// Maps between a MIR Location, which identifies a particular
 /// statement within a basic block, to a "rich location", which
@@ -17,7 +17,7 @@
     statements_before_block: IndexVec<BasicBlock, usize>,
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct LocationIndex {
         DEBUG_FORMAT = "LocationIndex({})"
     }
index cf80a1bc6437e040ee1eb0df5344169c57183704..cfa211ad5afdb9a28f4c324eb56113c1665b2144 100644 (file)
 use rustc::ty::{self, TyCtxt};
 
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::dominators::Dominators;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use smallvec::SmallVec;
 
 use std::collections::BTreeMap;
index d6b91373ab8250d9bf4d51ec6972e6fabd2bd1d7..8ab4020394ffdb8665e8af74fdc5833c6d7f9a29 100644 (file)
@@ -5,7 +5,7 @@
     Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind
 };
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use syntax_pos::Span;
 use syntax_pos::symbol::kw;
 
index b5630251e5830942b194ebc3edcc61c8b3d71a8a..b6a9a7ee6578fc35dc67a8dda3e25b0f42752f73 100644 (file)
@@ -4,7 +4,7 @@
 use rustc::mir::ConstraintCategory;
 use rustc::ty::RegionVid;
 use rustc_data_structures::graph;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use syntax_pos::DUMMY_SP;
 
 /// The construct graph organizes the constraints by their end-points.
index 6121ed0cf0d1c3282b87dc813de3f85b294e8407..93113753c630bfbf6061b812395fd0adad0a1946 100644 (file)
@@ -2,7 +2,7 @@
 use rustc::mir::ConstraintCategory;
 use rustc::ty::RegionVid;
 use rustc_data_structures::graph::scc::Sccs;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use std::fmt;
 use std::ops::Index;
 
@@ -100,13 +100,13 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct OutlivesConstraintIndex {
         DEBUG_FORMAT = "OutlivesConstraintIndex({})"
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct ConstraintSccIndex {
         DEBUG_FORMAT = "ConstraintSccIndex({})"
     }
index f0beb4d3ae32d773e4afc09aa9a6a07b02f5c589..13e5769c5bea8a777b0d8216af992be36a0c2c37 100644 (file)
@@ -4,7 +4,7 @@
 use polonius_engine::Atom;
 use rustc::mir::Local;
 use rustc::ty::{RegionVid, TyCtxt};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use std::error::Error;
 use std::fmt::Debug;
 use std::fs::{self, File};
index b5e2e111f38e518828a10d30581ed9badf3adef3..fd195873a55e48a4d9e757ce2150cf013e4c4f68 100644 (file)
@@ -2,7 +2,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::infer::region_constraints::MemberConstraint;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use std::hash::Hash;
 use std::ops::Index;
 use syntax_pos::Span;
@@ -51,7 +51,7 @@
     end_index: usize,
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     crate struct NllMemberConstraintIndex {
         DEBUG_FORMAT = "MemberConstraintIndex({})"
     }
index 1ff3228afa376fc198b77732948152ac56b65b2c..b2e5751b902e7a9d566a0fe8fa49bbd7a4fa8111 100644 (file)
@@ -14,7 +14,7 @@
 use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
                  Local, Location, Body, LocalKind, BasicBlock, Promoted};
 use rustc::ty::{self, RegionKind, RegionVid};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_errors::Diagnostic;
 use std::fmt::Debug;
 use std::env;
index e29e9232012bc52f8e67b82f9b660657a03c159b..6d3f2e566382f8059ab3db36910e62ac8ac9aee9 100644 (file)
@@ -12,7 +12,7 @@
 use rustc::infer::NLLRegionVariableOrigin;
 use rustc::mir::{ConstraintCategory, Location, Body};
 use rustc::ty::{self, RegionVid};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_errors::DiagnosticBuilder;
 use std::collections::VecDeque;
 use syntax::errors::Applicability;
index 750a1324faeb3de025ba76910d2d1e0d6086aa0e..7f0e97c9ae4264a5f555f75c82e3e65dfa5d3217 100644 (file)
@@ -3,7 +3,7 @@
 use crate::borrow_check::Upvar;
 use rustc::mir::{Local, Body};
 use rustc::ty::{RegionVid, TyCtxt};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use syntax::source_map::Span;
 use syntax_pos::symbol::Symbol;
 
index 78e7943598d68ad7eb8761fe5f3bd935b04ef2c1..38df8035397123ac2fb66c366fd24939b9e5e48b 100644 (file)
 use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc::util::common::ErrorReported;
 use rustc_data_structures::binary_search_util;
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::WithSuccessors;
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_data_structures::graph::vec_graph::VecGraph;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_errors::{Diagnostic, DiagnosticBuilder};
 use syntax_pos::Span;
 
index 6f9f5707935baa75ef782903d642681a23279e41..6acbff76bdc90a4ca5d74a53f648c8b0a540b647 100644 (file)
@@ -1,9 +1,9 @@
 use rustc::mir::{BasicBlock, Location, Body};
 use rustc::ty::{self, RegionVid};
-use rustc_data_structures::bit_set::{HybridBitSet, SparseBitMatrix};
+use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::Idx;
+use rustc_index::vec::IndexVec;
 use std::fmt::Debug;
 use std::rc::Rc;
 
@@ -116,13 +116,13 @@ impl RegionValueElements {
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     /// A single integer representing a `Location` in the MIR control-flow
     /// graph. Constructed efficiently from `RegionValueElements`.
     pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     /// A single integer representing a `ty::Placeholder`.
     pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
 }
index c479c38f30c7ea9dcfe23bad512e991804854266..cd13803875b5d44f7bd2599b172cef644387edb3 100644 (file)
@@ -3,7 +3,7 @@
 use rustc::mir::{Location, Body, Promoted};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 
 /// Replaces all free regions appearing in the MIR with fresh
 /// inference variables, returning the number of variables created.
index 99661b1f7370ab888f7b8ff1f1c5f9d2e651bf51..d74dd0fc0f5f148f8a61ff50fdb40166f2e29d4a 100644 (file)
@@ -12,7 +12,7 @@
 use rustc::mir::*;
 use rustc::ty::Ty;
 
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use syntax_pos::Span;
 
 use super::{Locations, TypeChecker};
index 049d83bb22f1bc9cf48a56606bca4fdfb93adc02..7689ece706695c0acce58afabcc4de6b6e2d069f 100644 (file)
@@ -2,7 +2,7 @@
 use crate::util::liveness::{categorize, DefUse};
 use rustc::mir::visit::{PlaceContext, Visitor};
 use rustc::mir::{Body, Local, Location};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_data_structures::vec_linked_list as vll;
 
 /// A map that cross references each local with the locations where it
@@ -44,7 +44,7 @@ struct Appearance {
     next: Option<AppearanceIndex>,
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct AppearanceIndex { .. }
 }
 
index 9b55881cb1b10162a4e24b3d7657748b043e90b5..36482a7b13534f56433df3b0068e4345019fffff 100644 (file)
@@ -12,7 +12,7 @@
 use rustc::traits::query::type_op::outlives::DropckOutlives;
 use rustc::traits::query::type_op::TypeOp;
 use rustc::ty::{Ty, TypeFoldable};
-use rustc_data_structures::bit_set::HybridBitSet;
+use rustc_index::bit_set::HybridBitSet;
 use rustc_data_structures::fx::FxHashMap;
 use std::rc::Rc;
 
index fa326062fe2c9c20bcaab4de5f2d43fa154efa4a..b24ba596d7e93a4d9f9dee9603381e018661300a 100644 (file)
@@ -43,7 +43,7 @@
     UserTypeAnnotationIndex,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 use rustc::ty::layout::VariantIdx;
 use std::rc::Rc;
 use std::{fmt, iter, mem};
index 7053bdca25957117829d25331c3901f57ea160c7..b4470582b7145d332f083c12ee0213eb2c14d351 100644 (file)
@@ -21,7 +21,7 @@
 use rustc::ty::subst::{InternalSubsts, SubstsRef, Subst};
 use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_errors::DiagnosticBuilder;
 use std::iter;
 
index 09b33c6654a9db084a0bc431d1ed99bc81e54ec8..17308119339fd4e2daef1075a500d4c448e75776 100644 (file)
@@ -8,7 +8,7 @@
 use rustc::mir::*;
 use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
 
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a place that we can move from etc.
index 7dfe98cbebfc27f0e09d07d55de1138eaf344c8d..b4d93a4493fd9b14b8648f75d60608ad10f7e0fb 100644 (file)
@@ -1,7 +1,7 @@
 //! See docs in `build/expr/mod.rs`.
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 
 use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
index 8db06aa375e238066ac010bbfaadf5437fee6fad..861de07c612e9bbaaa9b2f23616a946167161c99 100644 (file)
@@ -15,7 +15,7 @@
 use rustc::middle::region;
 use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty};
 use rustc::ty::layout::VariantIdx;
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use syntax::ast::Name;
 use syntax_pos::Span;
index d8bb0b4f6cc57d3c091912d254d1795e1630d683..a04c989e6e0debacf82ec1bb259d350dbf09c7f4 100644 (file)
@@ -9,9 +9,9 @@
 use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
 use crate::hair::*;
 use crate::hair::pattern::compare_const_vals;
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc_data_structures::fx::FxHashMap;
-use rustc::ty::{self, Ty, adjustment::{PointerCast}};
+use rustc::ty::{self, Ty, adjustment::PointerCast};
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::layout::VariantIdx;
 use rustc::mir::*;
index 17932ae855767bc44fe94001aed3a4b6230bf64c..9c30d9509908b7e89520929a7aa26beda4cc0659 100644 (file)
@@ -14,7 +14,7 @@
 use rustc::ty::subst::Subst;
 use rustc::util::nodemap::HirIdMap;
 use rustc_target::spec::PanicStrategy;
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 use std::u32;
 use rustc_target::spec::abi::Abi;
 use syntax::attr::{self, UnwindAttr};
@@ -455,7 +455,7 @@ struct CFG<'tcx> {
     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct ScopeId { .. }
 }
 
index f0014602e2d6b161089727ccbcf901fcf80c8362..e0ca10535237bd3c0bf87c820c97ba74d9c68b90 100644 (file)
@@ -2,7 +2,7 @@
 //! locations.
 
 use rustc::mir::{BasicBlock, Location};
-use rustc_data_structures::bit_set::{BitIter, BitSet, HybridBitSet};
+use rustc_index::bit_set::{BitIter, BitSet, HybridBitSet};
 
 use crate::dataflow::{BitDenotation, DataflowResults, GenKillSet};
 use crate::dataflow::move_paths::{HasMoveData, MovePathIndex};
index 886044c0692829e2c283e2e3cb10586c16ef1ef0..dd6238b80d1744115ea4615de706806a728afa48 100644 (file)
 //! [gk]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
 //! [#64566]: https://github.com/rust-lang/rust/pull/64566
 
+use std::borrow::Borrow;
 use std::cmp::Ordering;
-use std::ops;
+use std::ffi::OsString;
+use std::path::{Path, PathBuf};
+use std::{fs, io, ops};
 
+use rustc::hir::def_id::DefId;
 use rustc::mir::{self, traversal, BasicBlock, Location};
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::work_queue::WorkQueue;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::{Idx, IndexVec};
+use syntax::symbol::sym;
 
 use crate::dataflow::BottomValue;
 
+mod graphviz;
+
 /// A specific kind of dataflow analysis.
 ///
 /// To run a dataflow analysis, one must set the initial state of the `START_BLOCK` via
@@ -62,6 +70,13 @@ pub trait Analysis<'tcx>: BottomValue {
     /// and try to keep it short.
     const NAME: &'static str;
 
+    /// How each element of your dataflow state will be displayed during debugging.
+    ///
+    /// By default, this is the `fmt::Debug` representation of `Self::Idx`.
+    fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> {
+        write!(w, "{:?}", idx)
+    }
+
     /// The size of each bitvector allocated for each block.
     fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize;
 
@@ -77,7 +92,7 @@ fn apply_statement_effect(
         location: Location,
     );
 
-    /// Updates the current dataflow state with the effect of evaluating a statement.
+    /// Updates the current dataflow state with the effect of evaluating a terminator.
     ///
     /// Note that the effect of a successful return from a `Call` terminator should **not** be
     /// acounted for in this function. That should go in `apply_call_return_effect`. For example,
@@ -180,17 +195,20 @@ fn block(&self) -> BasicBlock {
     }
 }
 
+type ResultsRefCursor<'a, 'mir, 'tcx, A> =
+    ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
+
 /// Inspect the results of dataflow analysis.
 ///
 /// This cursor has linear performance when visiting statements in a block in order. Visiting
 /// statements within a block in reverse order is `O(n^2)`, where `n` is the number of statements
 /// in that block.
-pub struct ResultsCursor<'mir, 'tcx, A>
+pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
 where
     A: Analysis<'tcx>,
 {
     body: &'mir mir::Body<'tcx>,
-    results: Results<'tcx, A>,
+    results: R,
     state: BitSet<A::Idx>,
 
     pos: CursorPosition,
@@ -202,24 +220,29 @@ pub struct ResultsCursor<'mir, 'tcx, A>
     is_call_return_effect_applied: bool,
 }
 
-impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A>
+impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
 where
     A: Analysis<'tcx>,
+    R: Borrow<Results<'tcx, A>>,
 {
     /// Returns a new cursor for `results` that points to the start of the `START_BLOCK`.
-    pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
+    pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
         ResultsCursor {
             body,
             pos: CursorPosition::AtBlockStart(mir::START_BLOCK),
             is_call_return_effect_applied: false,
-            state: results.entry_sets[mir::START_BLOCK].clone(),
+            state: results.borrow().entry_sets[mir::START_BLOCK].clone(),
             results,
         }
     }
 
+    pub fn analysis(&self) -> &A {
+        &self.results.borrow().analysis
+    }
+
     /// Resets the cursor to the start of the given `block`.
     pub fn seek_to_block_start(&mut self, block: BasicBlock) {
-        self.state.overwrite(&self.results.entry_sets[block]);
+        self.state.overwrite(&self.results.borrow().entry_sets[block]);
         self.pos = CursorPosition::AtBlockStart(block);
         self.is_call_return_effect_applied = false;
     }
@@ -275,7 +298,7 @@ pub fn seek_after_assume_call_returns(&mut self, target: Location) {
         } = &term.kind {
             if !self.is_call_return_effect_applied {
                 self.is_call_return_effect_applied = true;
-                self.results.analysis.apply_call_return_effect(
+                self.results.borrow().analysis.apply_call_return_effect(
                     &mut self.state,
                     target.block,
                     func,
@@ -316,7 +339,7 @@ fn _seek_after(&mut self, target: Location) {
         };
 
         let block_data = &self.body.basic_blocks()[target_block];
-        self.results.analysis.apply_partial_block_effect(
+        self.results.borrow().analysis.apply_partial_block_effect(
             &mut self.state,
             target_block,
             block_data,
@@ -349,7 +372,9 @@ pub struct Engine<'a, 'tcx, A>
 {
     analysis: A,
     bits_per_block: usize,
+    tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
+    def_id: DefId,
     dead_unwinds: &'a BitSet<BasicBlock>,
     entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
 }
@@ -359,7 +384,9 @@ impl<A> Engine<'a, 'tcx, A>
     A: Analysis<'tcx>,
 {
     pub fn new(
+        tcx: TyCtxt<'tcx>,
         body: &'a mir::Body<'tcx>,
+        def_id: DefId,
         dead_unwinds: &'a BitSet<BasicBlock>,
         analysis: A,
     ) -> Self {
@@ -377,7 +404,9 @@ pub fn new(
         Engine {
             analysis,
             bits_per_block,
+            tcx,
             body,
+            def_id,
             dead_unwinds,
             entry_sets,
         }
@@ -413,10 +442,26 @@ pub fn iterate_to_fixpoint(mut self) -> Results<'tcx, A> {
             );
         }
 
-        Results {
-            analysis: self.analysis,
-            entry_sets: self.entry_sets,
+        let Engine {
+            tcx,
+            body,
+            def_id,
+            analysis,
+            entry_sets,
+            ..
+        } = self;
+
+        let results = Results { analysis, entry_sets };
+
+        let attrs = tcx.get_attrs(def_id);
+        if let Some(path) = get_dataflow_graphviz_output_path(tcx, attrs, A::NAME) {
+            let result = write_dataflow_graphviz_results(body, def_id, &path, &results);
+            if let Err(e) = result {
+                warn!("Failed to write dataflow results to {}: {}", path.display(), e);
+            }
         }
+
+        results
     }
 
     fn propagate_bits_into_graph_successors_of(
@@ -510,3 +555,59 @@ fn propagate_bits_into_entry_set_for(
         }
     }
 }
+
+/// Looks for attributes like `#[rustc_mir(borrowck_graphviz_postflow="./path/to/suffix.dot")]` and
+/// extracts the path with the given analysis name prepended to the suffix.
+///
+/// Returns `None` if no such attribute exists.
+fn get_dataflow_graphviz_output_path(
+    tcx: TyCtxt<'tcx>,
+    attrs: ty::Attributes<'tcx>,
+    analysis: &str,
+) -> Option<PathBuf> {
+    let mut rustc_mir_attrs = attrs
+        .into_iter()
+        .filter(|attr| attr.check_name(sym::rustc_mir))
+        .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
+
+    let borrowck_graphviz_postflow = rustc_mir_attrs
+        .find(|attr| attr.check_name(sym::borrowck_graphviz_postflow))?;
+
+    let path_and_suffix = match borrowck_graphviz_postflow.value_str() {
+        Some(p) => p,
+        None => {
+            tcx.sess.span_err(
+                borrowck_graphviz_postflow.span(),
+                "borrowck_graphviz_postflow requires a path",
+            );
+
+            return None;
+        }
+    };
+
+    // Change "path/suffix.dot" to "path/analysis_name_suffix.dot"
+    let mut ret = PathBuf::from(path_and_suffix.to_string());
+    let suffix = ret.file_name().unwrap();
+
+    let mut file_name: OsString = analysis.into();
+    file_name.push("_");
+    file_name.push(suffix);
+    ret.set_file_name(file_name);
+
+    Some(ret)
+}
+
+fn write_dataflow_graphviz_results<A: Analysis<'tcx>>(
+    body: &mir::Body<'tcx>,
+    def_id: DefId,
+    path: &Path,
+    results: &Results<'tcx, A>
+) -> io::Result<()> {
+    debug!("printing dataflow results for {:?} to {}", def_id, path.display());
+
+    let mut buf = Vec::new();
+    let graphviz = graphviz::Formatter::new(body, def_id, results);
+
+    dot::render(&graphviz, &mut buf)?;
+    fs::write(path, buf)
+}
diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs
new file mode 100644 (file)
index 0000000..2a08fef
--- /dev/null
@@ -0,0 +1,412 @@
+use std::cell::RefCell;
+use std::io::{self, Write};
+use std::{ops, str};
+
+use rustc::hir::def_id::DefId;
+use rustc::mir::{self, BasicBlock, Body, Location};
+use rustc_index::bit_set::{BitSet, HybridBitSet};
+use rustc_index::vec::Idx;
+
+use crate::util::graphviz_safe_def_name;
+use super::{Analysis, Results, ResultsRefCursor};
+
+pub struct Formatter<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    body: &'a Body<'tcx>,
+    def_id: DefId,
+
+    // This must be behind a `RefCell` because `dot::Labeller` takes `&self`.
+    block_formatter: RefCell<BlockFormatter<'a, 'tcx, A>>,
+}
+
+impl<A> Formatter<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    pub fn new(
+        body: &'a Body<'tcx>,
+        def_id: DefId,
+        results: &'a Results<'tcx, A>,
+    ) -> Self {
+        let block_formatter = BlockFormatter {
+            bg: Background::Light,
+            prev_state: BitSet::new_empty(results.analysis.bits_per_block(body)),
+            results: ResultsRefCursor::new(body, results),
+        };
+
+        Formatter {
+            body,
+            def_id,
+            block_formatter: RefCell::new(block_formatter),
+        }
+    }
+}
+
+/// A pair of a basic block and an index into that basic blocks `successors`.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct CfgEdge {
+    source: BasicBlock,
+    index: usize,
+}
+
+fn outgoing_edges(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
+    body[bb]
+        .terminator()
+        .successors()
+        .enumerate()
+        .map(|(index, _)| CfgEdge { source: bb, index })
+        .collect()
+}
+
+impl<A> dot::Labeller<'_> for Formatter<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    type Node = BasicBlock;
+    type Edge = CfgEdge;
+
+    fn graph_id(&self) -> dot::Id<'_> {
+        let name = graphviz_safe_def_name(self.def_id);
+        dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
+    }
+
+    fn node_id(&self, n: &Self::Node) -> dot::Id<'_> {
+        dot::Id::new(format!("bb_{}", n.index())).unwrap()
+    }
+
+    fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
+        let mut label = Vec::new();
+        self.block_formatter
+            .borrow_mut()
+            .write_node_label(&mut label, self.body, *block)
+            .unwrap();
+        dot::LabelText::html(String::from_utf8(label).unwrap())
+    }
+
+    fn node_shape(&self, _n: &Self::Node) -> Option<dot::LabelText<'_>> {
+        Some(dot::LabelText::label("none"))
+    }
+
+    fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> {
+        let label = &self.body
+            [e.source]
+            .terminator()
+            .kind
+            .fmt_successor_labels()
+            [e.index];
+        dot::LabelText::label(label.clone())
+    }
+}
+
+impl<A> dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    type Node = BasicBlock;
+    type Edge = CfgEdge;
+
+    fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
+        self.body
+            .basic_blocks()
+            .indices()
+            .collect::<Vec<_>>()
+            .into()
+    }
+
+    fn edges(&self) -> dot::Edges<'_, Self::Edge> {
+        self.body
+            .basic_blocks()
+            .indices()
+            .flat_map(|bb| outgoing_edges(self.body, bb))
+            .collect::<Vec<_>>()
+            .into()
+    }
+
+    fn source(&self, edge: &Self::Edge) -> Self::Node {
+        edge.source
+    }
+
+    fn target(&self, edge: &Self::Edge) -> Self::Node {
+        self.body
+            [edge.source]
+            .terminator()
+            .successors()
+            .nth(edge.index)
+            .copied()
+            .unwrap()
+    }
+}
+
+struct BlockFormatter<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    prev_state: BitSet<A::Idx>,
+    results: ResultsRefCursor<'a, 'a, 'tcx, A>,
+    bg: Background,
+}
+
+impl<A> BlockFormatter<'a, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    fn toggle_background(&mut self) -> Background {
+        let bg = self.bg;
+        self.bg = !bg;
+        bg
+    }
+
+    fn write_node_label(
+        &mut self,
+        w: &mut impl io::Write,
+        body: &'a Body<'tcx>,
+        block: BasicBlock,
+    ) -> io::Result<()> {
+        //   Sample output:
+        //   +-+--------------------------------------------------+
+        // A |                         bb4                        |
+        //   +-+----------------------------------+---------------+
+        // B |               MIR                  |     STATE     |
+        //   +-+----------------------------------+---------------+
+        // C | | (on entry)                       | {_0,_2,_3}    |
+        //   +-+----------------------------------+---------------+
+        // D |0|  0: StorageLive(_7)              |               |
+        //   +-+----------------------------------+---------------+
+        //   |1|  1: StorageLive(_8)              |               |
+        //   +-+----------------------------------+---------------+
+        //   |2|  2: _8 = &mut _1                 | +_8           |
+        //   +-+----------------------------------+---------------+
+        // E |T| _7 = const Foo::twiddle(move _8) | -_8           |
+        //   +-+----------------------------------+---------------+
+        // F | | (on unwind)                      | {_0,_2,_3,_7} |
+        //   +-+----------------------------------+---------------+
+        //   | | (on successful return)           | +_7           |
+        //   +-+----------------------------------+---------------+
+
+        write!(
+            w,
+            r#"<table border="1" cellborder="1" cellspacing="0" cellpadding="3" sides="rb">"#,
+        )?;
+
+        // A: Block info
+        write!(
+            w,
+            r#"<tr>
+                 <td colspan="{num_headers}" sides="tl">bb{block_id}</td>
+               </tr>"#,
+            num_headers = 3,
+            block_id = block.index(),
+        )?;
+
+        // B: Column headings
+        write!(
+            w,
+            r#"<tr>
+                 <td colspan="2" {fmt}>MIR</td>
+                 <td {fmt}>STATE</td>
+               </tr>"#,
+            fmt = r##"bgcolor="#a0a0a0" sides="tl""##,
+        )?;
+
+        // C: Entry state
+        self.results.seek_to_block_start(block);
+        self.write_row_with_curr_state(w, "", "(on entry)")?;
+        self.prev_state.overwrite(self.results.get());
+
+        // D: Statement transfer functions
+        for (i, statement) in body[block].statements.iter().enumerate() {
+            let location = Location { block, statement_index: i };
+
+            let mir_col = format!("{:?}", statement);
+            let i_col = i.to_string();
+
+            self.results.seek_after(location);
+            self.write_row_with_curr_diff(w, &i_col, &mir_col)?;
+            self.prev_state.overwrite(self.results.get());
+        }
+
+        // E: Terminator transfer function
+        let terminator = body[block].terminator();
+        let location = body.terminator_loc(block);
+
+        let mut mir_col = String::new();
+        terminator.kind.fmt_head(&mut mir_col).unwrap();
+
+        self.results.seek_after(location);
+        self.write_row_with_curr_diff(w, "T", &mir_col)?;
+        self.prev_state.overwrite(self.results.get());
+
+        // F: Exit state
+        if let mir::TerminatorKind::Call { destination: Some(_), ..  } = &terminator.kind {
+            self.write_row_with_curr_state(w, "", "(on unwind)")?;
+
+            self.results.seek_after_assume_call_returns(location);
+            self.write_row_with_curr_diff(w, "", "(on successful return)")?;
+        } else {
+            self.write_row_with_curr_state(w, "", "(on exit)")?;
+        }
+
+        write!(w, "</table>")
+    }
+
+    fn write_row_with_curr_state(
+        &mut self,
+        w: &mut impl io::Write,
+        i: &str,
+        mir: &str,
+    ) -> io::Result<()> {
+        let bg = self.toggle_background();
+
+        let mut out = Vec::new();
+        write!(&mut out, "{{")?;
+        pretty_print_state_elems(&mut out, self.results.analysis(), self.results.get().iter())?;
+        write!(&mut out, "}}")?;
+
+        write!(
+            w,
+            r#"<tr>
+                 <td {fmt} align="right">{i}</td>
+                 <td {fmt} align="left">{mir}</td>
+                 <td {fmt} align="left">{state}</td>
+               </tr>"#,
+            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
+            i = i,
+            mir = dot::escape_html(mir),
+            state = dot::escape_html(str::from_utf8(&out).unwrap()),
+        )
+    }
+
+    fn write_row_with_curr_diff(
+        &mut self,
+        w: &mut impl io::Write,
+        i: &str,
+        mir: &str,
+    ) -> io::Result<()> {
+        let bg = self.toggle_background();
+        let analysis = self.results.analysis();
+
+        let diff = BitSetDiff::compute(&self.prev_state, self.results.get());
+
+        let mut set = Vec::new();
+        pretty_print_state_elems(&mut set, analysis, diff.set.iter())?;
+
+        let mut clear = Vec::new();
+        pretty_print_state_elems(&mut clear, analysis, diff.clear.iter())?;
+
+        write!(
+            w,
+            r#"<tr>
+                 <td {fmt} align="right">{i}</td>
+                 <td {fmt} align="left">{mir}</td>
+                 <td {fmt} align="left">"#,
+            i = i,
+            fmt = &["sides=\"tl\"", bg.attr()].join(" "),
+            mir = dot::escape_html(mir),
+        )?;
+
+        if !set.is_empty() {
+            write!(
+                w,
+                r#"<font color="darkgreen">+{}</font>"#,
+                dot::escape_html(str::from_utf8(&set).unwrap()),
+            )?;
+        }
+
+        if !set.is_empty() && !clear.is_empty() {
+            write!(w, "  ")?;
+        }
+
+        if !clear.is_empty() {
+            write!(
+                w,
+                r#"<font color="red">-{}</font>"#,
+                dot::escape_html(str::from_utf8(&clear).unwrap()),
+            )?;
+        }
+
+        write!(w, "</td></tr>")
+    }
+}
+
+/// The operations required to transform one `BitSet` into another.
+struct BitSetDiff<T: Idx> {
+    set: HybridBitSet<T>,
+    clear: HybridBitSet<T>,
+}
+
+impl<T: Idx> BitSetDiff<T> {
+    fn compute(from: &BitSet<T>, to: &BitSet<T>) -> Self {
+        assert_eq!(from.domain_size(), to.domain_size());
+        let len = from.domain_size();
+
+        let mut set = HybridBitSet::new_empty(len);
+        let mut clear = HybridBitSet::new_empty(len);
+
+        // FIXME: This could be made faster if `BitSet::xor` were implemented.
+        for i in (0..len).map(|i| T::new(i)) {
+            match (from.contains(i), to.contains(i)) {
+                (false, true) => set.insert(i),
+                (true, false) => clear.insert(i),
+                _ => continue,
+            };
+        }
+
+        BitSetDiff {
+            set,
+            clear,
+        }
+    }
+}
+
+/// Formats each `elem` using the pretty printer provided by `analysis` into a comma-separated
+/// list.
+fn pretty_print_state_elems<A>(
+    w: &mut impl io::Write,
+    analysis: &A,
+    elems: impl Iterator<Item = A::Idx>,
+) -> io::Result<()>
+where
+    A: Analysis<'tcx>,
+{
+    let mut first = true;
+    for idx in elems {
+        if first {
+            first = false;
+        } else {
+            write!(w, ",")?;
+        }
+
+        analysis.pretty_print_idx(w, idx)?;
+    }
+
+    Ok(())
+}
+
+/// The background color used for zebra-striping the table.
+#[derive(Clone, Copy)]
+enum Background {
+    Light,
+    Dark,
+}
+
+impl Background {
+    fn attr(self) -> &'static str {
+        match self {
+            Self::Dark => "bgcolor=\"#f0f0f0\"",
+            Self::Light => "",
+        }
+    }
+}
+
+impl ops::Not for Background {
+    type Output = Self;
+
+    fn not(self) -> Self {
+        match self {
+            Self::Light => Self::Dark,
+            Self::Dark => Self::Light,
+        }
+    }
+}
index a86fcb30f4d36ca97bbf7c94fec381eaf69e9834..5e64144df2cd1c371d93d4b1b995017f191f3fd3 100644 (file)
@@ -5,9 +5,9 @@
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::RegionVid;
 
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 
 use crate::dataflow::{BitDenotation, BottomValue, GenKillSet};
 use crate::borrow_check::nll::region_infer::RegionInferenceContext;
@@ -16,7 +16,7 @@
 
 use std::rc::Rc;
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct BorrowIndex {
         DEBUG_FORMAT = "bw{}"
     }
index 7d20248ebd1f567cdad232410d926ee1cc7304dd..535b803b85f35cc3b9140a765f50fa842dbd72e7 100644 (file)
@@ -1,7 +1,7 @@
 use rustc::mir::visit::Visitor;
 use rustc::mir::{self, Local, Location};
 use rustc::ty::{self, TyCtxt};
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use syntax_pos::DUMMY_SP;
 
 use crate::dataflow::{self, GenKillSet};
index d669c786c09df984a5b0edcbcccef29197eb945e..6f860d00a22c2d5eaf699119b9123ebe622f16c1 100644 (file)
@@ -4,8 +4,8 @@
 
 use rustc::ty::TyCtxt;
 use rustc::mir::{self, Body, Location};
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::Idx;
 
 use super::MoveDataParamEnv;
 
index 47eb47cf664ded1c239a46546b79b1e90975c6d5..06999abdc8b264025f1136dddb88153e67f14c9e 100644 (file)
@@ -1,8 +1,8 @@
 use syntax::ast::{self, MetaItem};
 use syntax::symbol::{Symbol, sym};
 
-use rustc_data_structures::bit_set::{BitSet, HybridBitSet};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::bit_set::{BitSet, HybridBitSet};
+use rustc_index::vec::Idx;
 use rustc_data_structures::work_queue::WorkQueue;
 
 use rustc::hir::def_id::DefId;
index d9119253cae5fe833273f08e0d19f4d77e8e3f21..53b18e4364b95e03da6f9ed6ef7462b443f93971 100644 (file)
@@ -1,7 +1,7 @@
 use rustc::mir::tcx::RvalueInitializationState;
 use rustc::mir::*;
 use rustc::ty::{self, TyCtxt};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use smallvec::{smallvec, SmallVec};
 
 use std::collections::hash_map::Entry;
index 156c19c6363e58a74ffd4077f7af571112617979..f5a03316d809c0f8bbbd84d0b85dd3b40e17c606 100644 (file)
@@ -2,7 +2,7 @@
 use rustc::mir::*;
 use rustc::ty::{Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::indexed_vec::{Enumerated, Idx, IndexVec};
+use rustc_index::vec::{Enumerated, Idx, IndexVec};
 use smallvec::SmallVec;
 use syntax_pos::Span;
 
 
 mod abs_domain;
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct MovePathIndex {
         DEBUG_FORMAT = "mp{}"
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct MoveOutIndex {
         DEBUG_FORMAT = "mo{}"
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct InitIndex {
         DEBUG_FORMAT = "in{}"
     }
index 196bcf147f8f81ad2abc6b489a539b22598768f4..fb1311de9a70659bf14855cfc9fa9f1bc302e176 100644 (file)
@@ -1128,6 +1128,51 @@ unsafe impl<T> Sync for NotThreadSafe<T> {}
 cell are synchronized.
 "##,
 
+E0493: r##"
+A type with a `Drop` implementation was destructured when trying to initialize
+a static item.
+
+Erroneous code example:
+
+```compile_fail,E0493
+enum DropType {
+    A,
+}
+
+impl Drop for DropType {
+    fn drop(&mut self) {}
+}
+
+struct Foo {
+    field1: DropType,
+}
+
+static FOO: Foo = Foo { ..Foo { field1: DropType::A } }; // error!
+```
+
+The problem here is that if the given type or one of its fields implements the
+`Drop` trait, this `Drop` implementation cannot be called during the static
+type initialization which might cause a memory leak. To prevent this issue,
+you need to instantiate all the static type's fields by hand.
+
+```
+enum DropType {
+    A,
+}
+
+impl Drop for DropType {
+    fn drop(&mut self) {}
+}
+
+struct Foo {
+    field1: DropType,
+}
+
+static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields
+                                               // by hand.
+```
+"##,
+
 E0499: r##"
 A variable was borrowed as mutable more than once. Erroneous code example:
 
@@ -2454,7 +2499,6 @@ const fn foo() -> impl T {
 //  E0299, // mismatched types between arms
 //  E0471, // constant evaluation error (in pattern)
 //  E0385, // {} in an aliasable location
-    E0493, // destructors cannot be evaluated at compile-time
     E0521, // borrowed data escapes outside of closure
     E0526, // shuffle indices are not constant
     E0594, // cannot assign to {}
index 33d67dcf914480f5d2bf344a5b83490bf5de4d43..e9777dab26e2a5cd5c52dc9352f4d3422244a2d5 100644 (file)
@@ -5,7 +5,7 @@
 use rustc::hir;
 use rustc::ty;
 
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
     type Output = Block<'tcx>;
index eed51cdab8c3cf2845906b06475f7778863923df..db314cb5fafd48c5cad23da21d065263153acbb0 100644 (file)
@@ -3,7 +3,7 @@
 use crate::hair::cx::block;
 use crate::hair::cx::to_ref::ToRef;
 use crate::hair::util::UserAnnotatedTyHelpers;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind};
 use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue};
 use rustc::ty::{self, AdtKind, Ty};
index 32efbd6f011730d92a381491462f66dc22c606fc..e120b496d3d09c57eea70c65f447d07537fd0f3f 100644 (file)
@@ -5,7 +5,7 @@
 use crate::hair::*;
 use crate::hair::util::UserAnnotatedTyHelpers;
 
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc::hir::def_id::DefId;
 use rustc::hir::Node;
 use rustc::middle::region;
index 75a84f6ec648b6dec057bc4fb00705574679817c..d3bc61a4dde560b69cc62125108ed2ded5c4f963 100644 (file)
 use self::WitnessPreference::*;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 
 use super::{FieldPat, Pat, PatKind, PatRange};
 use super::{PatternFoldable, PatternFolder, compare_const_vals};
index 4d2fee3d160ede89a684f6a4b7f39bc21959991b..58d741b9295a3b209dd4652b75a50f5996f8fcfe 100644 (file)
 use rustc::lint;
 use rustc::mir::{Field, BorrowKind, Mutability};
 use rustc::mir::{UserTypeProjection};
-use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer};
+use rustc::mir::interpret::{GlobalId, ConstValue, get_slice_bytes, sign_extend};
 use rustc::traits::{ObligationCause, PredicateObligation};
 use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree};
 use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
 use rustc::ty::subst::{SubstsRef, GenericArg};
-use rustc::ty::layout::{VariantIdx, Size};
+use rustc::ty::layout::VariantIdx;
 use rustc::hir::{self, RangeEnd};
 use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::hir::ptr::P;
 
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc_data_structures::fx::FxHashSet;
 
 use std::cmp::Ordering;
@@ -1526,27 +1526,10 @@ pub fn compare_const_vals<'tcx>(
 
     if let ty::Str = ty.kind {
         match (a.val, b.val) {
-            (
-                ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a },
-                ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b },
-            ) => {
-                let len_a = end_a - offset_a;
-                let len_b = end_b - offset_b;
-                let a = alloc_a.get_bytes(
-                    &tcx,
-                    // invent a pointer, only the offset is relevant anyway
-                    Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)),
-                    Size::from_bytes(len_a as u64),
-                );
-                let b = alloc_b.get_bytes(
-                    &tcx,
-                    // invent a pointer, only the offset is relevant anyway
-                    Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)),
-                    Size::from_bytes(len_b as u64),
-                );
-                if let (Ok(a), Ok(b)) = (a, b) {
-                    return from_bool(a == b);
-                }
+            (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => {
+                let a_bytes = get_slice_bytes(&tcx, a.val);
+                let b_bytes = get_slice_bytes(&tcx, b.val);
+                return from_bool(a_bytes == b_bytes);
             }
             _ => (),
         }
index fdf85260c3d961273e0079ad5e9994f3e993ae11..e1c45132103b450049f70cd48db64fb62be236d9 100644 (file)
@@ -12,7 +12,7 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::query::TyCtxtAt;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc::mir::interpret::{
     GlobalId, Scalar, Pointer, FrameInfo, AllocId,
     InterpResult, truncate, sign_extend,
index 4c7d0dcb697211d72e0227299793664b2fc1f43d..7ce151e087a6bcaff56548228870bfc067341753 100644 (file)
@@ -17,7 +17,7 @@
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::layout::{Align, Size};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use syntax::ast::Mutability;
 use syntax::source_map::Span;
index 4f978051eaccdd8383bc8bde9bf8c9a47720d1a4..da3fead1f9dd7e5cc1b7aa4cc0d238a5627c36f7 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
index cc8f4759e183791d20e2f3e52370c380495ba93d..9c58e2aa16c1d02e7f88b9ea320408c7f6fd990d 100644 (file)
 use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
 use rustc::util::common::time;
 
-use rustc_data_structures::bit_set::GrowableBitSet;
+use rustc_index::bit_set::GrowableBitSet;
 use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter};
 
 use std::iter;
index 4fae0976ffb5a1302c9c4a05e31f4a5b08a265c9..7303880602e9255678fbc01bbaa0fb8079deda66 100644 (file)
@@ -6,7 +6,7 @@
 use rustc::ty::subst::{Subst, InternalSubsts};
 use rustc::ty::query::Providers;
 
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 
 use rustc_target::spec::abi::Abi;
 use syntax_pos::{Span, sym};
index 15ecc6c37920b5c87f6eee616ed3540001326505..bf3df1ae2fd8484ab6fa6919427a61488b20f029 100644 (file)
@@ -1,6 +1,6 @@
 use rustc::ty::TyCtxt;
 use rustc::mir::*;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use crate::transform::{MirPass, MirSource};
 
 #[derive(PartialEq)]
index d9d0ce18555730be2d096e188a87112bfbc33f78..40007eb3c4a3ef71d4543c827a028b630ca8dcf8 100644 (file)
@@ -3,7 +3,7 @@
 use rustc::mir::*;
 use rustc::mir::interpret::ConstValue;
 use rustc::ty::{self, Ty};
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use syntax_pos::DUMMY_SP;
 
 use super::Item as ConstCx;
@@ -27,6 +27,9 @@ fn contains<Q: ?Sized + Qualif>(self) -> bool {
 pub trait Qualif {
     const IDX: usize;
 
+    /// The name of the file used to debug the dataflow analysis that computes this qualif.
+    const ANALYSIS_NAME: &'static str;
+
     /// Whether this `Qualif` is cleared when a local is moved from.
     const IS_CLEARED_ON_MOVE: bool = false;
 
@@ -207,6 +210,7 @@ fn in_call(
 
 impl Qualif for HasMutInterior {
     const IDX: usize = 0;
+    const ANALYSIS_NAME: &'static str = "flow_has_mut_interior";
 
     fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
         !ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP)
@@ -264,6 +268,7 @@ fn in_rvalue(cx: &ConstCx<'_, 'tcx>, per_local: &BitSet<Local>, rvalue: &Rvalue<
 
 impl Qualif for NeedsDrop {
     const IDX: usize = 1;
+    const ANALYSIS_NAME: &'static str = "flow_needs_drop";
     const IS_CLEARED_ON_MOVE: bool = true;
 
     fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
index 2789693ecb6ec25100988cb78b5b25475b036b54..4fa4eba4c23b6ebca2ffdc5047ea95e4b0ba1e08 100644 (file)
@@ -5,7 +5,7 @@
 
 use rustc::mir::visit::Visitor;
 use rustc::mir::{self, BasicBlock, Local, Location};
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 
 use std::cell::RefCell;
 use std::marker::PhantomData;
@@ -208,7 +208,8 @@ pub fn new(
             _qualif: PhantomData,
         };
         let results =
-            dataflow::Engine::new(item.body, dead_unwinds, analysis).iterate_to_fixpoint();
+            dataflow::Engine::new(item.tcx, item.body, item.def_id, dead_unwinds, analysis)
+                .iterate_to_fixpoint();
         let cursor = dataflow::ResultsCursor::new(item.body, results);
 
         let mut qualifs_in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
@@ -308,7 +309,7 @@ impl<Q> dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 {
     type Idx = Local;
 
-    const NAME: &'static str = "flow_sensitive_qualif";
+    const NAME: &'static str = Q::ANALYSIS_NAME;
 
     fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
         body.local_decls.len()
index 7e876dd1d9980da097a839e8e9343a15bf405c00..3045239d7a7701ba9cdf5370961211085585d298 100644 (file)
@@ -5,7 +5,7 @@
 use rustc::mir::*;
 use rustc::ty::cast::CastTy;
 use rustc::ty::{self, TyCtxt};
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use rustc_target::spec::abi::Abi;
 use syntax::symbol::sym;
 use syntax_pos::Span;
@@ -467,8 +467,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
 
         self.qualifs.needs_drop.visit_statement(statement, location);
         self.qualifs.has_mut_interior.visit_statement(statement, location);
-        debug!("needs_drop: {:?}", self.qualifs.needs_drop.get());
-        debug!("has_mut_interior: {:?}", self.qualifs.has_mut_interior.get());
 
         match statement.kind {
             StatementKind::Assign(..) => {
@@ -494,8 +492,6 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
 
         self.qualifs.needs_drop.visit_terminator(terminator, location);
         self.qualifs.has_mut_interior.visit_terminator(terminator, location);
-        debug!("needs_drop: {:?}", self.qualifs.needs_drop.get());
-        debug!("has_mut_interior: {:?}", self.qualifs.has_mut_interior.get());
 
         self.super_terminator(terminator, location);
     }
index acd53ac68ae3f27d4290f8f20f9ee72217808fce..70855d70228b3536e8456b04c665e180a8f46e6c 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::sync::Lrc;
 
 use rustc::ty::query::Providers;
index 612822b6d9d34362d41a9d0d1170023fb2089ccb..f34bfbeab3b47bf445a01f838fb59dc45b892315 100644 (file)
@@ -21,7 +21,7 @@
 use syntax_pos::{Span, DUMMY_SP};
 use rustc::ty::subst::InternalSubsts;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc::ty::layout::{
     LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout,
 };
index d7b6810a8659afe3fced73bfde74880497d8eba2..f91a08bcd9aa6349bad6776129a54d3cf414e0f2 100644 (file)
@@ -14,7 +14,7 @@
 use rustc::hir;
 use rustc::mir::*;
 use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use std::fmt;
 use syntax_pos::Span;
 
index 2b66e602370cca03153c8f6f2b5878384988b681..bfc5eb5a94ef88ea37410dc1a6e3f9ffb96c4b5e 100644 (file)
@@ -58,8 +58,8 @@
 use rustc::ty::layout::VariantIdx;
 use rustc::ty::subst::SubstsRef;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc_data_structures::bit_set::{BitSet, BitMatrix};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::bit_set::{BitSet, BitMatrix};
 use std::borrow::Cow;
 use std::iter;
 use std::mem;
index 7f56c6f7986aa4afba53fd668553b5fde7be7bd2..9830ed35ffc3ed0b10ed8bfc890b6cfe37fb51f6 100644 (file)
@@ -3,8 +3,8 @@
 use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::def_id::DefId;
 
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::{Idx, IndexVec};
 
 use rustc::mir::*;
 use rustc::mir::visit::*;
index 6b609e25ec0424d675ef8ff0e451e1111d53cbef..bb98d63b1ee10b4b317588e2aecc3b658d40ebc1 100644 (file)
@@ -5,7 +5,7 @@
 use rustc::mir::visit::{MutVisitor, Visitor};
 use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use std::mem;
 use crate::transform::{MirPass, MirSource};
 
index 5037c791cb68892fc26fddf110ed621bc0af4a69..7e06729c2c742df9b41361b703738c05ce5d53d8 100644 (file)
@@ -1,5 +1,5 @@
 use crate::{build, shim};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::mir::{Body, MirPhase, Promoted};
 use rustc::ty::{TyCtxt, InstanceDef};
index 7d1b96b8be170dc89d11cde8d5194285a88cf723..5d241ffe1c06a6860c98c42b40cb34538fdaac98 100644 (file)
@@ -20,7 +20,7 @@
 use rustc::ty::TyCtxt;
 use syntax_pos::Span;
 
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 
 use std::{iter, mem, usize};
 
index 387540655f07b72665109053a466d1a1e867d84a..2fa6b9d1a29366ef1096657f031f5cb0a562e408 100644 (file)
@@ -4,8 +4,8 @@
 //! The Qualif flags below can be used to also provide better
 //! diagnostics as to why a constant rvalue wasn't promoted.
 
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_target::spec::abi::Abi;
 use rustc::hir;
index 70b11944e2fbcc463288cf09b745cd47a5121fc1..e1994c5f639b0e0882c1bfb2dc003d23355f99d8 100644 (file)
@@ -1,6 +1,6 @@
 use rustc::ty::TyCtxt;
 use rustc::mir::*;
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use crate::transform::{MirPass, MirSource};
 use crate::util::patch::MirPatch;
 
index 539645d0227f4b912b7eca1e3ce8265adf0de7ed..f509d2d7104eb31961ad26e23c8be10c93681b7d 100644 (file)
@@ -6,7 +6,7 @@
 use rustc::ty::{self, TyCtxt};
 use rustc::hir::def_id::DefId;
 use rustc::mir::{self, Body, Location};
-use rustc_data_structures::bit_set::BitSet;
+use rustc_index::bit_set::BitSet;
 use crate::transform::{MirPass, MirSource};
 
 use crate::dataflow::{do_dataflow, DebugFormatted};
index d4599ee08aa4614f43c8db3c37b3808bdeb95e83..9ffff9a92fa53d041255af2ac45ce90c17f1af05 100644 (file)
@@ -27,8 +27,8 @@
 //! naively generate still contains the `_a = ()` write in the unreachable block "after" the
 //! return.
 
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc::ty::TyCtxt;
 use rustc::mir::*;
 use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext};
index eb61cd2f657a2a681930cf12412b4eaa75d1049e..efa39d91205b467ba3f260dbd64bb15b6320ab2a 100644 (file)
@@ -30,7 +30,7 @@
 use rustc::ty::TyCtxt;
 use rustc::mir::*;
 use rustc::mir::visit::{Visitor, PlaceContext, NonUseContext};
-use rustc_data_structures::indexed_vec::{IndexVec};
+use rustc_index::vec::{IndexVec};
 use crate::transform::{MirPass, MirSource};
 use crate::util::patch::MirPatch;
 
index b3565d40b8e217e9bdab4f4f2a737adfb3654481..c0f921857455683d52f12e409306143e90feece8 100644 (file)
@@ -1,7 +1,7 @@
 use rustc::mir::*;
 use rustc::ty::Ty;
 use rustc::ty::layout::VariantIdx;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 
 use std::iter::TrustedLen;
 
index 59821440c6619cfb2edded3d832b1a19281201a4..3aea25fa8769fe708623e42c8b86a97c97ee9f7b 100644 (file)
@@ -2,7 +2,7 @@
 
 use rustc::mir::{Local, Location, Body};
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_index::vec::IndexVec;
 use std::mem;
 
 pub struct DefUseAnalysis {
index e1015edfa8eec791d2a7ea32b0857758b570731f..37b9398f9cb612233a4bf9db46f284d20104e44c 100644 (file)
@@ -7,7 +7,7 @@
 use rustc::ty::layout::VariantIdx;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::util::IntTypeExt;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use crate::util::patch::MirPatch;
 
 use std::convert::TryInto;
index 9d142d9b700b63498f26f180c88c03233be4258d..7fcb7a40a3c0893d5cdbd8a291236fb516dbfabd 100644 (file)
@@ -1,7 +1,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir::*;
 use rustc::ty::TyCtxt;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use std::fmt::Debug;
 use std::io::{self, Write};
 
index b42eebc7ee3be28dfc0cd3d1cf544b7623535a1b..9757f4ac392ec8d8e273f9417f6d99cb8f587b33 100644 (file)
@@ -30,8 +30,8 @@
 use rustc::mir::Local;
 use rustc::mir::*;
 use rustc::ty::{self, TyCtxt};
-use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_data_structures::work_queue::WorkQueue;
 use std::fs;
 use std::io::{self, Write};
index 2ea9924af7f28d427ccb150392262f8ce2032056..a5f7e5401573bd606ac6374e06397e21166954d0 100644 (file)
@@ -1,6 +1,6 @@
 use rustc::ty::Ty;
 use rustc::mir::*;
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 use syntax_pos::Span;
 
 /// This struct represents a patch to MIR, which can add
index c35c9e4da9f4846be217a9cabc0ed3205f56d0c9..7f6b60b1b116b48877fb18214adab1247407c997 100644 (file)
@@ -3,7 +3,7 @@
 use rustc::mir::visit::Visitor;
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use std::fmt::Display;
 use std::fmt::Write as _;
 use std::fs;
index 0d35cc53ac6f38037ad162ccf5c7389f7c43c013..d3bf82b66ad1cf163a9310ecf28db381196ddd01 100644 (file)
@@ -348,7 +348,7 @@ fn smart_resolve_context_dependent_help(
             _ => false,
         };
 
-        let mut bad_struct_syntax_suggestion = || {
+        let mut bad_struct_syntax_suggestion = |def_id: DefId| {
             let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
             let mut suggested = false;
             match source {
@@ -374,6 +374,9 @@ fn smart_resolve_context_dependent_help(
                 _ => {}
             }
             if !suggested {
+                if let Some(span) = self.r.definitions.opt_span(def_id) {
+                    err.span_label(span, &format!("`{}` defined here", path_str));
+                }
                 err.span_label(
                     span,
                     format!("did you mean `{} {{ /* fields */ }}`?", path_str),
@@ -437,18 +440,21 @@ fn smart_resolve_context_dependent_help(
                         );
                     }
                 } else {
-                    bad_struct_syntax_suggestion();
+                    bad_struct_syntax_suggestion(def_id);
                 }
             }
-            (Res::Def(DefKind::Union, _), _) |
-            (Res::Def(DefKind::Variant, _), _) |
-            (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _), _) if ns == ValueNS => {
-                bad_struct_syntax_suggestion();
+            (Res::Def(DefKind::Union, def_id), _) |
+            (Res::Def(DefKind::Variant, def_id), _) |
+            (Res::Def(DefKind::Ctor(_, CtorKind::Fictive), def_id), _) if ns == ValueNS => {
+                bad_struct_syntax_suggestion(def_id);
             }
-            (Res::Def(DefKind::Ctor(_, CtorKind::Fn), _), _) if ns == ValueNS => {
+            (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
+                if let Some(span) = self.r.definitions.opt_span(def_id) {
+                    err.span_label(span, &format!("`{}` defined here", path_str));
+                }
                 err.span_label(
                     span,
-                    format!("did you mean `{} ( /* fields */ )`?", path_str),
+                    format!("did you mean `{}( /* fields */ )`?", path_str),
                 );
             }
             (Res::SelfTy(..), _) if ns == ValueNS => {
index cab1e0e01371d73c8a3ddc4d8e3deb37d20ae1ee..fba2ea02bb44ac45131310fa62cb35cc8022c5c1 100644 (file)
@@ -14,3 +14,4 @@ log = "0.4"
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax_pos = { path = "../libsyntax_pos" }
+rustc_index = { path = "../librustc_index" }
index dafa866117681df8c2d2016a27a8b7587bad0355..26d37f196befac3b9f15ed3b8e0d25af295043cc 100644 (file)
@@ -6,8 +6,7 @@
 use std::fmt;
 use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
 
-use rustc_data_structures::newtype_index;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexVec};
 use syntax_pos::symbol::{sym, Symbol};
 use syntax_pos::Span;
 
@@ -844,7 +843,7 @@ pub fn is_uninhabited(&self) -> bool {
     }
 }
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct VariantIdx { .. }
 }
 
index ac3966676838aac88d3979275e0b9234a3a94f5f..a6644258be280082764c5b18d898972fe9e1268b 100644 (file)
@@ -20,3 +20,4 @@ rustc_target = { path = "../librustc_target" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
+rustc_index = { path = "../librustc_index" }
index 13b6b1b8aa08dc332652e09e851a404e2dcfbd40..a1daed005f3024ae79a1bd20dedd406cf5288896 100644 (file)
@@ -36,7 +36,7 @@ pub fn check_match(
             // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`.
             //
             // FIXME(60707): Consider removing hack with principled solution.
-            self.check_expr_has_type_or_error(discrim, self.tcx.types.bool)
+            self.check_expr_has_type_or_error(discrim, self.tcx.types.bool, |_| {})
         } else {
             self.demand_discriminant_type(arms, discrim)
         };
@@ -106,7 +106,9 @@ pub fn check_match(
             if let Some(g) = &arm.guard {
                 self.diverges.set(pats_diverge);
                 match g {
-                    hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool),
+                    hir::Guard::If(e) => {
+                        self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {})
+                    }
                 };
             }
 
@@ -442,7 +444,7 @@ fn demand_discriminant_type(
                 kind: TypeVariableOriginKind::TypeInference,
                 span: discrim.span,
             });
-            self.check_expr_has_type_or_error(discrim, discrim_ty);
+            self.check_expr_has_type_or_error(discrim, discrim_ty, |_| {});
             discrim_ty
         }
     }
index 564a0eac7553977690c1f6acffb03b4fc227640c..56962d53a645064b4ff9ea9d735a86eaa9f23e58 100644 (file)
@@ -1163,18 +1163,20 @@ fn coerce_inner<'a>(
                 fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No)
             } else {
                 match self.expressions {
-                    Expressions::Dynamic(ref exprs) =>
-                        fcx.try_find_coercion_lub(cause,
-                                                  exprs,
-                                                  self.merged_ty(),
-                                                  expression,
-                                                  expression_ty),
-                    Expressions::UpFront(ref coercion_sites) =>
-                        fcx.try_find_coercion_lub(cause,
-                                                  &coercion_sites[0..self.pushed],
-                                                  self.merged_ty(),
-                                                  expression,
-                                                  expression_ty),
+                    Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub(
+                        cause,
+                        exprs,
+                        self.merged_ty(),
+                        expression,
+                        expression_ty,
+                    ),
+                    Expressions::UpFront(ref coercion_sites) => fcx.try_find_coercion_lub(
+                        cause,
+                        &coercion_sites[0..self.pushed],
+                        self.merged_ty(),
+                        expression,
+                        expression_ty,
+                    ),
                 }
             }
         } else {
@@ -1216,7 +1218,7 @@ fn coerce_inner<'a>(
                     self.pushed += 1;
                 }
             }
-            Err(err) => {
+            Err(coercion_error) => {
                 let (expected, found) = if label_expression_as_expected {
                     // In the case where this is a "forced unit", like
                     // `break`, we want to call the `()` "expected"
@@ -1232,41 +1234,42 @@ fn coerce_inner<'a>(
                     (self.final_ty.unwrap_or(self.expected_ty), expression_ty)
                 };
 
-                let mut db;
+                let mut err;
                 match cause.code {
                     ObligationCauseCode::ReturnNoExpression => {
-                        db = struct_span_err!(
+                        err = struct_span_err!(
                             fcx.tcx.sess, cause.span, E0069,
                             "`return;` in a function whose return type is not `()`");
-                        db.span_label(cause.span, "return type is not `()`");
+                        err.span_label(cause.span, "return type is not `()`");
                     }
                     ObligationCauseCode::BlockTailExpression(blk_id) => {
                         let parent_id = fcx.tcx.hir().get_parent_node(blk_id);
-                        db = self.report_return_mismatched_types(
+                        err = self.report_return_mismatched_types(
                             cause,
                             expected,
                             found,
-                            err,
+                            coercion_error,
                             fcx,
                             parent_id,
                             expression.map(|expr| (expr, blk_id)),
                         );
                     }
                     ObligationCauseCode::ReturnValue(id) => {
-                        db = self.report_return_mismatched_types(
-                            cause, expected, found, err, fcx, id, None);
+                        err = self.report_return_mismatched_types(
+                            cause, expected, found, coercion_error, fcx, id, None);
                     }
                     _ => {
-                        db = fcx.report_mismatched_types(cause, expected, found, err);
+                        err = fcx.report_mismatched_types(cause, expected, found, coercion_error);
                     }
                 }
 
                 if let Some(augment_error) = augment_error {
-                    augment_error(&mut db);
+                    augment_error(&mut err);
                 }
 
                 // Error possibly reported in `check_assign` so avoid emitting error again.
-                db.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some());
+                err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
+                    .is_some());
 
                 self.final_ty = Some(fcx.tcx.types.err);
             }
@@ -1278,12 +1281,12 @@ fn report_return_mismatched_types<'a>(
         cause: &ObligationCause<'tcx>,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
-        err: TypeError<'tcx>,
+        ty_err: TypeError<'tcx>,
         fcx: &FnCtxt<'a, 'tcx>,
         id: hir::HirId,
         expression: Option<(&'tcx hir::Expr, hir::HirId)>,
     ) -> DiagnosticBuilder<'a> {
-        let mut db = fcx.report_mismatched_types(cause, expected, found, err);
+        let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
 
         let mut pointing_at_return_type = false;
         let mut return_sp = None;
@@ -1294,7 +1297,7 @@ fn report_return_mismatched_types<'a>(
         let parent_id = fcx.tcx.hir().get_parent_node(id);
         let fn_decl = if let Some((expr, blk_id)) = expression {
             pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
-                &mut db,
+                &mut err,
                 expr,
                 expected,
                 found,
@@ -1302,6 +1305,16 @@ fn report_return_mismatched_types<'a>(
                 blk_id,
             );
             let parent = fcx.tcx.hir().get(parent_id);
+            if let (Some(match_expr), true, false) = (
+                fcx.tcx.hir().get_match_if_cause(expr.hir_id),
+                expected.is_unit(),
+                pointing_at_return_type,
+            ) {
+                if match_expr.span.desugaring_kind().is_none() {
+                    err.span_label(match_expr.span, "expected this to be `()`");
+                    fcx.suggest_semicolon_at_end(match_expr.span, &mut err);
+                }
+            }
             fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
         } else {
             fcx.get_fn_decl(parent_id)
@@ -1310,20 +1323,20 @@ fn report_return_mismatched_types<'a>(
         if let (Some((fn_decl, can_suggest)), _) = (fn_decl, pointing_at_return_type) {
             if expression.is_none() {
                 pointing_at_return_type |= fcx.suggest_missing_return_type(
-                    &mut db, &fn_decl, expected, found, can_suggest);
+                    &mut err, &fn_decl, expected, found, can_suggest);
             }
             if !pointing_at_return_type {
                 return_sp = Some(fn_decl.output.span()); // `impl Trait` return type
             }
         }
         if let (Some(sp), Some(return_sp)) = (fcx.ret_coercion_span.borrow().as_ref(), return_sp) {
-            db.span_label(return_sp, "expected because this return type...");
-            db.span_label( *sp, format!(
+            err.span_label(return_sp, "expected because this return type...");
+            err.span_label( *sp, format!(
                 "...is found to be `{}` here",
                 fcx.resolve_type_vars_with_obligations(expected),
             ));
         }
-        db
+        err
     }
 
     pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
index 6bed321d27f82a92bd7037a82b3b890cca5786c9..04c8536de8dfef423b0430a8cfc8c0f1066f83ad 100644 (file)
@@ -53,14 +53,16 @@ pub fn check_expr_has_type_or_error(
         &self,
         expr: &'tcx hir::Expr,
         expected: Ty<'tcx>,
+        extend_err: impl Fn(&mut DiagnosticBuilder<'_>),
     ) -> Ty<'tcx> {
-        self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected))
+        self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err)
     }
 
     fn check_expr_meets_expectation_or_error(
         &self,
         expr: &'tcx hir::Expr,
         expected: Expectation<'tcx>,
+        extend_err: impl Fn(&mut DiagnosticBuilder<'_>),
     ) -> Ty<'tcx> {
         let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool);
         let mut ty = self.check_expr_with_expectation(expr, expected);
@@ -88,6 +90,7 @@ fn check_expr_meets_expectation_or_error(
                 ExprKind::DropTemps(expr) => expr,
                 _ => expr,
             };
+            extend_err(&mut err);
             // Error possibly reported in `check_assign` so avoid emitting error again.
             err.emit_unless(self.is_assign_to_bool(expr, expected_ty));
         }
@@ -971,7 +974,7 @@ fn check_expr_repeat(
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: element.span,
                 });
-                let element_ty = self.check_expr_has_type_or_error(&element, ty);
+                let element_ty = self.check_expr_has_type_or_error(&element, ty, |_| {});
                 (element_ty, ty)
             }
         };
@@ -1058,7 +1061,7 @@ fn check_expr_struct(
             // the fields with the base_expr. This could cause us to hit errors later
             // when certain fields are assumed to exist that in fact do not.
             if !error_happened {
-                self.check_expr_has_type_or_error(base_expr, adt_ty);
+                self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
                 match adt_ty.kind {
                     ty::Adt(adt, substs) if adt.is_struct() => {
                         let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
index a7832b8c2cf1727217762cf1911bd5939cb6d450..5e3db1c7990d0a6817fc6b8be47b9cc52aabeaa9 100644 (file)
@@ -99,7 +99,7 @@
 use crate::namespace::Namespace;
 use rustc::infer::{self, InferCtxt, InferOk, InferResult};
 use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 use rustc_target::spec::abi::Abi;
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -3879,6 +3879,15 @@ fn overwrite_local_ty_if_err(&self, local: &'tcx hir::Local, decl_ty: Ty<'tcx>,
         }
     }
 
+    fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) {
+        err.span_suggestion_short(
+            span.shrink_to_hi(),
+            "consider using a semicolon here",
+            ";".to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+
     pub fn check_stmt(&self, stmt: &'tcx hir::Stmt) {
         // Don't do all the complex logic below for `DeclItem`.
         match stmt.kind {
@@ -3902,7 +3911,10 @@ pub fn check_stmt(&self, stmt: &'tcx hir::Stmt) {
             hir::StmtKind::Item(_) => {}
             hir::StmtKind::Expr(ref expr) => {
                 // Check with expected type of `()`.
-                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit());
+
+                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
+                    self.suggest_semicolon_at_end(expr.span, err);
+                });
             }
             hir::StmtKind::Semi(ref expr) => {
                 self.check_expr(&expr);
index e11dcfafb8f8b1f10b31972b543b838fd716e0f2..3a07171b12fb80160016eb7a83463f41d141aa5f 100644 (file)
@@ -3610,6 +3610,43 @@ fn fly(&self) {} // And now that's ok!
 ```
 "##,
 
+E0533: r##"
+An item which isn't a unit struct, a variant, nor a constant has been used as a
+match pattern.
+
+Erroneous code example:
+
+```compile_fail,E0533
+struct Tortoise;
+
+impl Tortoise {
+    fn turtle(&self) -> u32 { 0 }
+}
+
+match 0u32 {
+    Tortoise::turtle => {} // Error!
+    _ => {}
+}
+if let Tortoise::turtle = 0u32 {} // Same error!
+```
+
+If you want to match against a value returned by a method, you need to bind the
+value first:
+
+```
+struct Tortoise;
+
+impl Tortoise {
+    fn turtle(&self) -> u32 { 0 }
+}
+
+match 0u32 {
+    x if x == Tortoise.turtle() => {} // Bound into `x` then we compare it!
+    _ => {}
+}
+```
+"##,
+
 E0534: r##"
 The `inline` attribute was malformed.
 
@@ -4935,7 +4972,6 @@ fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
     E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
            // between structures with the same definition
 //  E0558, // replaced with a generic attribute input check
-    E0533, // `{}` does not name a unit variant, unit struct or a constant
 //  E0563, // cannot determine a type for this `impl Trait` removed in 6383de15
     E0564, // only named lifetimes are allowed in `impl Trait`,
            // but `{}` was found in the type `{}`
index b530851b80de7c52983a20169fbbad9177f92fce..8f35ca01f79df2c8349109e9fa2ad95aca54374c 100644 (file)
@@ -9,7 +9,7 @@
 mod auto_trait;
 mod blanket_impl;
 
-use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_index::vec::{IndexVec, Idx};
 use rustc_target::spec::abi::Abi;
 use rustc_typeck::hir_ty_to_ty;
 use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
index 301dddbbfb9b2e748a51b02554270d83c44fa986..1ff71a0024b28c853d54285ddd5e2b60a084fd2e 100644 (file)
@@ -574,7 +574,7 @@ fn write_shared(
 
     let write = |p, c| { cx.shared.fs.write(p, c) };
     if (*cx.shared).layout.logo.is_empty() {
-        write(cx.path("rust-log.png"), static_files::RUST_LOGO)?;
+        write(cx.path("rust-logo.png"), static_files::RUST_LOGO)?;
     }
     if (*cx.shared).layout.favicon.is_empty() {
         write(cx.path("favicon.ico"), static_files::RUST_FAVICON)?;
index 2985e7f70b52f649b0dce3c67243b749ebc10d81..539bf5dfe28e629fff59367218888c7853f6ad0e 100644 (file)
@@ -25,6 +25,7 @@
 extern crate env_logger;
 extern crate rustc;
 extern crate rustc_data_structures;
+extern crate rustc_index;
 extern crate rustc_driver;
 extern crate rustc_resolve;
 extern crate rustc_lint;
index 196cf4d9dfae8d3fb35b0c6a697f3528d991d50c..d8de21cc6778f1cdffc39cdfa211d91a209529fb 100644 (file)
@@ -18,6 +18,7 @@ lazy_static = "1.0.0"
 syntax_pos = { path = "../libsyntax_pos" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_index = { path = "../librustc_index" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
index bc468c1ad0ebe549ac74b387de36b1c149f5067d..023952042e6d478ce13b0d3d3e1d629144a9a0b1 100644 (file)
@@ -14,7 +14,7 @@
 use crate::tokenstream::TokenStream;
 use crate::ThinVec;
 
-use rustc_data_structures::indexed_vec::Idx;
+use rustc_index::vec::Idx;
 #[cfg(target_arch = "x86_64")]
 use rustc_data_structures::static_assert_size;
 use rustc_target::spec::abi::Abi;
@@ -241,9 +241,8 @@ pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
 
 // hack to ensure that we don't try to access the private parts of `NodeId` in this module
 mod node_id_inner {
-    use rustc_data_structures::indexed_vec::Idx;
-    use rustc_data_structures::newtype_index;
-    newtype_index! {
+    use rustc_index::vec::Idx;
+    rustc_index::newtype_index! {
         pub struct NodeId {
             ENCODABLE = custom
             DEBUG_FORMAT = "NodeId({})"
@@ -2140,18 +2139,29 @@ fn decode<D: Decoder>(d: &mut D) -> Result<AttrId, D::Error> {
     }
 }
 
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub struct AttrItem {
+    pub path: Path,
+    pub tokens: TokenStream,
+}
+
 /// Metadata associated with an item.
 /// Doc-comments are promoted to attributes that have `is_sugared_doc = true`.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Attribute {
+    pub item: AttrItem,
     pub id: AttrId,
     pub style: AttrStyle,
-    pub path: Path,
-    pub tokens: TokenStream,
     pub is_sugared_doc: bool,
     pub span: Span,
 }
 
+// Compatibility impl to avoid churn, consider removing.
+impl std::ops::Deref for Attribute {
+    type Target = AttrItem;
+    fn deref(&self) -> &Self::Target { &self.item }
+}
+
 /// `TraitRef`s appear in impls.
 ///
 /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all
index 122cb7fb12b246b44f742b565788a11dc849189f..7bef693a5be4cce1bb3fcf4d202add442587d515 100644 (file)
@@ -9,7 +9,7 @@
 pub use crate::ast::Attribute;
 
 use crate::ast;
-use crate::ast::{AttrId, AttrStyle, Name, Ident, Path, PathSegment};
+use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
 use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
 use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
 use crate::mut_visit::visit_clobber;
@@ -255,9 +255,8 @@ pub fn is_meta_item_list(&self) -> bool {
     }
 }
 
-impl Attribute {
-    /// Extracts the `MetaItem` from inside this `Attribute`.
-    pub fn meta(&self) -> Option<MetaItem> {
+impl AttrItem {
+    crate fn meta(&self, span: Span) -> Option<MetaItem> {
         let mut tokens = self.tokens.trees().peekable();
         Some(MetaItem {
             path: self.path.clone(),
@@ -269,9 +268,16 @@ pub fn meta(&self) -> Option<MetaItem> {
             } else {
                 return None;
             },
-            span: self.span,
+            span,
         })
     }
+}
+
+impl Attribute {
+    /// Extracts the MetaItem from inside this Attribute.
+    pub fn meta(&self) -> Option<MetaItem> {
+        self.item.meta(self.span)
+    }
 
     pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
@@ -333,10 +339,9 @@ pub fn with_desugared_doc<T, F>(&self, f: F) -> T where
                 DUMMY_SP,
             );
             f(&Attribute {
+                item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
                 id: self.id,
                 style: self.style,
-                path: meta.path,
-                tokens: meta.kind.tokens(meta.span),
                 is_sugared_doc: true,
                 span: self.span,
             })
@@ -384,10 +389,9 @@ pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
 
 pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute {
     Attribute {
+        item: AttrItem { path, tokens },
         id: mk_attr_id(),
         style,
-        path,
-        tokens,
         is_sugared_doc: false,
         span,
     }
@@ -408,10 +412,12 @@ pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute {
     let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
     let lit = Lit::from_lit_kind(lit_kind, span);
     Attribute {
+        item: AttrItem {
+            path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
+            tokens: MetaItemKind::NameValue(lit).tokens(span),
+        },
         id: mk_attr_id(),
         style,
-        path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
-        tokens: MetaItemKind::NameValue(lit).tokens(span),
         is_sugared_doc: true,
         span,
     }
@@ -524,7 +530,7 @@ fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
             }
             Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
                 token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
-                token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
+                token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
                 token::Nonterminal::NtPath(ref path) => path.clone(),
                 _ => return None,
             },
index 990358c674ff76eae1e678753f767296babede75..2923cc86ba029a16c9b3cb8d6347bbd545e12b34 100644 (file)
@@ -122,8 +122,8 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
 
             while !parser.check(&token::CloseDelim(token::Paren)) {
                 let lo = parser.token.span.lo();
-                let (path, tokens) = parser.parse_meta_item_unrestricted()?;
-                expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo)));
+                let item = parser.parse_attr_item()?;
+                expanded_attrs.push((item, parser.prev_span.with_lo(lo)));
                 parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
             }
 
@@ -150,11 +150,10 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
             // `cfg_attr` inside of another `cfg_attr`. E.g.
             //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
             expanded_attrs.into_iter()
-            .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute {
+            .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute {
+                item,
                 id: attr::mk_attr_id(),
                 style: attr.style,
-                path,
-                tokens,
                 is_sugared_doc: false,
                 span,
             }))
index 9925dd8ada0d51520cf413608243e35a690784dc..8a78daee6e49b0a4c5a3bb83080387021e288071 100644 (file)
@@ -144,6 +144,25 @@ fn deprecated_function() {}
 ```
 "##,
 
+E0550: r##"
+More than one `deprecated` attribute has been put on an item.
+
+Erroneous code example:
+
+```compile_fail,E0550
+#[deprecated(note = "because why not?")]
+#[deprecated(note = "right?")] // error!
+fn the_banished() {}
+```
+
+The `deprecated` attribute can only be present **once** on an item.
+
+```
+#[deprecated(note = "because why not, right?")]
+fn the_banished() {} // ok!
+```
+"##,
+
 E0552: r##"
 A unrecognized representation attribute was used.
 
@@ -435,7 +454,6 @@ pub(in crate::foo) struct Bar {
     // rustc_deprecated attribute must be paired with either stable or unstable
     // attribute
     E0549,
-    E0550, // multiple deprecated attributes
     E0551, // incorrect meta item
     E0553, // multiple rustc_const_unstable attributes
 //  E0555, // replaced with a generic attribute input check
index 02e7c6775a49d1ed45098d7d27cdbd3bcfe8fa1b..bbd8da2acef0526121c251e1fe48ff18301e21e9 100644 (file)
@@ -1,4 +1,4 @@
-use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
+use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
 use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
 use crate::attr::{self, HasAttrs};
 use crate::source_map::respan;
@@ -555,15 +555,6 @@ fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
     }
 
     fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment {
-        let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
-        if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() {
-            if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else {
-                emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
-                                 span, GateIssue::Language,
-                                 "macro invocations in `extern {}` blocks are experimental");
-            }
-        }
-
         if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
             let expn_data = self.cx.current_expansion.id.expn_data();
             let suggested_limit = self.cx.ecfg.recursion_limit * 2;
@@ -578,6 +569,7 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstF
             FatalError.raise();
         }
 
+        let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
         match invoc.kind {
             InvocationKind::Bang { mac, .. } => match ext {
                 SyntaxExtensionKind::Bang(expander) => {
@@ -625,9 +617,10 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstF
                         | Annotatable::Variant(..)
                             => panic!("unexpected annotatable"),
                     })), DUMMY_SP).into();
-                    let input = self.extract_proc_macro_attr_input(attr.tokens, span);
+                    let input = self.extract_proc_macro_attr_input(attr.item.tokens, span);
                     let tok_result = expander.expand(self.cx, span, input, item_tok);
-                    let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span);
+                    let res =
+                        self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span);
                     self.gate_proc_macro_expansion(span, &res);
                     res
                 }
@@ -757,14 +750,14 @@ fn visit_mac(&mut self, _mac: &'ast ast::Mac) {
 
     fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) {
         let kind = match kind {
-            AstFragmentKind::Expr => "expressions",
+            AstFragmentKind::Expr |
             AstFragmentKind::OptExpr => "expressions",
             AstFragmentKind::Pat => "patterns",
-            AstFragmentKind::Ty => "types",
             AstFragmentKind::Stmts => "statements",
-            AstFragmentKind::Items => return,
-            AstFragmentKind::TraitItems => return,
-            AstFragmentKind::ImplItems => return,
+            AstFragmentKind::Ty |
+            AstFragmentKind::Items |
+            AstFragmentKind::TraitItems |
+            AstFragmentKind::ImplItems |
             AstFragmentKind::ForeignItems => return,
             AstFragmentKind::Arms
             | AstFragmentKind::Fields
@@ -1530,11 +1523,10 @@ fn visit_attribute(&mut self, at: &mut ast::Attribute) {
 
             let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
             *at = attr::Attribute {
+                item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
                 span: at.span,
                 id: at.id,
                 style: at.style,
-                path: meta.path,
-                tokens: meta.kind.tokens(meta.span),
                 is_sugared_doc: false,
             };
         } else {
@@ -1578,9 +1570,6 @@ pub fn default(crate_name: String) -> ExpansionConfig<'static> {
         }
     }
 
-    fn macros_in_extern(&self) -> bool {
-        self.features.map_or(false, |features| features.macros_in_extern)
-    }
     fn proc_macro_hygiene(&self) -> bool {
         self.features.map_or(false, |features| features.proc_macro_hygiene)
     }
index 8f49ba9572d774ba76c006020780f283f6101daa..d1c50fd85945de745e2db8b5038f68030b633bae 100644 (file)
@@ -924,7 +924,7 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
             FatalError.raise()
         }
         sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))),
-        sym::meta => token::NtMeta(panictry!(p.parse_meta_item())),
+        sym::meta => token::NtMeta(panictry!(p.parse_attr_item())),
         sym::vis => token::NtVis(panictry!(p.parse_visibility(true))),
         sym::lifetime => if p.check_lifetime() {
             token::NtLifetime(p.expect_lifetime().ident)
index 5538daf388e2f046e38a5c841be431ab0b4a6bc1..cda1ef1436ca1c8ae2161218753c2176339f319f 100644 (file)
@@ -245,6 +245,8 @@ macro_rules! declare_features {
     (accepted, bind_by_move_pattern_guards, "1.39.0", Some(15287), None),
     /// Allows attributes in formal function parameters.
     (accepted, param_attrs, "1.39.0", Some(60406), None),
+    // Allows macro invocations in `extern {}` blocks.
+    (accepted, macros_in_extern, "1.40.0", Some(49476), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index 38c16dbac6ab7730265fa7d8655e177b30ce92f8..47ee41f0adc1690b0d0de4e1437ba1906b61c1a1 100644 (file)
@@ -402,9 +402,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows infering `'static` outlives requirements (RFC 2093).
     (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
 
-    /// Allows macro invocations in `extern {}` blocks.
-    (active, macros_in_extern, "1.27.0", Some(49476), None),
-
     /// Allows accessing fields of unions inside `const` functions.
     (active, const_fn_union, "1.27.0", Some(51909), None),
 
index 2c10220c766a8ab4b64877d166d8c8c14376881a..d2c76b669dd5fef54014896c2e84ad4d20325c0d 100644 (file)
@@ -26,7 +26,7 @@
 
 pub use errors;
 use rustc_data_structures::sync::Lock;
-use rustc_data_structures::bit_set::GrowableBitSet;
+use rustc_index::bit_set::GrowableBitSet;
 pub use rustc_data_structures::thin_vec::ThinVec;
 use ast::AttrId;
 use syntax_pos::edition::Edition;
index 80dfe9e5be0ad60054ac8053220e36153c2cb3c7..3923b9f297b9ffaf897feb6b3b547529853a56b8 100644 (file)
@@ -550,7 +550,8 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
 }
 
 pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
-    let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr;
+    let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span }
+        = attr;
     vis.visit_path(path);
     vis.visit_tts(tokens);
     vis.visit_span(span);
@@ -681,7 +682,10 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
         token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
         token::NtLifetime(ident) => vis.visit_ident(ident),
         token::NtLiteral(expr) => vis.visit_expr(expr),
-        token::NtMeta(meta) => vis.visit_meta_item(meta),
+        token::NtMeta(AttrItem { path, tokens }) => {
+            vis.visit_path(path);
+            vis.visit_tts(tokens);
+        }
         token::NtPath(path) => vis.visit_path(path),
         token::NtTT(tt) => vis.visit_tt(tt),
         token::NtImplItem(item) =>
index 44688bd36b5fbb3182261e297b8a7240e9844411..e74f3045db80477b249c925c59f4cd033d8fe7de 100644 (file)
@@ -90,7 +90,7 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
         debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
                inner_parse_policy,
                self.token);
-        let (span, path, tokens, style) = match self.token.kind {
+        let (span, item, style) = match self.token.kind {
             token::Pound => {
                 let lo = self.token.span;
                 self.bump();
@@ -107,7 +107,7 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
                 };
 
                 self.expect(&token::OpenDelim(token::Bracket))?;
-                let (path, tokens) = self.parse_meta_item_unrestricted()?;
+                let item = self.parse_attr_item()?;
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 let hi = self.prev_span;
 
@@ -142,7 +142,7 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
                     }
                 }
 
-                (attr_sp, path, tokens, style)
+                (attr_sp, item, style)
             }
             _ => {
                 let token_str = self.this_token_to_string();
@@ -151,10 +151,9 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
         };
 
         Ok(ast::Attribute {
+            item,
             id: attr::mk_attr_id(),
             style,
-            path,
-            tokens,
             is_sugared_doc: false,
             span,
         })
@@ -167,19 +166,19 @@ fn parse_attribute_with_inner_parse_policy(&mut self,
     ///     PATH `[` TOKEN_STREAM `]`
     ///     PATH `{` TOKEN_STREAM `}`
     ///     PATH
-    ///     PATH `=` TOKEN_TREE
+    ///     PATH `=` UNSUFFIXED_LIT
     /// The delimiters or `=` are still put into the resulting token stream.
-    pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
-        let meta = match self.token.kind {
+    pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
+        let item = match self.token.kind {
             token::Interpolated(ref nt) => match **nt {
-                Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
+                Nonterminal::NtMeta(ref item) => Some(item.clone()),
                 _ => None,
             },
             _ => None,
         };
-        Ok(if let Some(meta) = meta {
+        Ok(if let Some(item) = item {
             self.bump();
-            (meta.path, meta.kind.tokens(meta.span))
+            item
         } else {
             let path = self.parse_path(PathStyle::Mod)?;
             let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
@@ -206,7 +205,7 @@ pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenS
             } else {
                 TokenStream::empty()
             };
-            (path, tokens)
+            ast::AttrItem { path, tokens }
         })
     }
 
@@ -263,7 +262,7 @@ fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
 
     /// Matches the following grammar (per RFC 1559).
     ///
-    ///     meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
+    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
     ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
         let nt_meta = match self.token.kind {
@@ -274,9 +273,14 @@ pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
             _ => None,
         };
 
-        if let Some(meta) = nt_meta {
-            self.bump();
-            return Ok(meta);
+        if let Some(item) = nt_meta {
+            return match item.meta(item.path.span) {
+                Some(meta) => {
+                    self.bump();
+                    Ok(meta)
+                }
+                None => self.unexpected(),
+            }
         }
 
         let lo = self.token.span;
index f22fd5ad703d9e4e7c80680e42f3fd9a374679fb..2fb6f197dad7c24ff4fda00cb8f66b7ab6e25165 100644 (file)
@@ -974,15 +974,22 @@ fn is_named_argument(&self) -> bool {
     /// This version of parse param doesn't necessarily require identifier names.
     fn parse_param_general(
         &mut self,
+        is_self_allowed: bool,
         is_trait_item: bool,
         allow_c_variadic: bool,
         is_name_required: impl Fn(&token::Token) -> bool,
     ) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
+
+        // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
         if let Some(mut param) = self.parse_self_param()? {
             param.attrs = attrs.into();
-            return self.recover_bad_self_param(param, is_trait_item);
+            return if is_self_allowed {
+                Ok(param)
+            } else {
+                self.recover_bad_self_param(param, is_trait_item)
+            };
         }
 
         let is_name_required = is_name_required(&self.token);
@@ -1207,6 +1214,7 @@ fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool)
                     }
                 };
             match p.parse_param_general(
+                false,
                 false,
                 allow_c_variadic,
                 do_not_enforce_named_arguments_for_c_variadic
@@ -1361,60 +1369,25 @@ fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
         Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
     }
 
-    /// Returns the parsed optional self parameter with attributes and whether a self
-    /// shortcut was used.
-    fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option<Param>> {
-        let attrs = self.parse_outer_attributes()?;
-        let param_opt = self.parse_self_param()?;
-        Ok(param_opt.map(|mut param| {
-            param.attrs = attrs.into();
-            param
-        }))
-    }
-
     /// Parses the parameter list and result type of a function that may have a `self` parameter.
-    fn parse_fn_decl_with_self<F>(&mut self, parse_param_fn: F) -> PResult<'a, P<FnDecl>>
-        where F: FnMut(&mut Parser<'a>) -> PResult<'a,  Param>,
-    {
-        self.expect(&token::OpenDelim(token::Paren))?;
-
-        // Parse optional self argument.
-        let self_param = self.parse_self_parameter_with_attrs()?;
-
-        // Parse the rest of the function parameter list.
-        let sep = SeqSep::trailing_allowed(token::Comma);
-        let (mut fn_inputs, recovered) = if let Some(self_param) = self_param {
-            if self.check(&token::CloseDelim(token::Paren)) {
-                (vec![self_param], false)
-            } else if self.eat(&token::Comma) {
-                let mut fn_inputs = vec![self_param];
-                let (mut input, _, recovered) = self.parse_seq_to_before_end(
-                    &token::CloseDelim(token::Paren), sep, parse_param_fn)?;
-                fn_inputs.append(&mut input);
-                (fn_inputs, recovered)
-            } else {
-                match self.expect_one_of(&[], &[]) {
-                    Err(err) => return Err(err),
-                    Ok(recovered) => (vec![self_param], recovered),
-                }
-            }
-        } else {
-            let (input, _, recovered) =
-                self.parse_seq_to_before_end(&token::CloseDelim(token::Paren),
-                                             sep,
-                                             parse_param_fn)?;
-            (input, recovered)
-        };
+    fn parse_fn_decl_with_self(
+        &mut self,
+        is_name_required: impl Copy + Fn(&token::Token) -> bool,
+    ) -> PResult<'a, P<FnDecl>> {
+        // Parse the arguments, starting out with `self` being allowed...
+        let mut is_self_allowed = true;
+        let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
+            let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
+            // ...but now that we've parsed the first argument, `self` is no longer allowed.
+            is_self_allowed = false;
+            res
+        })?;
 
-        if !recovered {
-            // Parse closing paren and return type.
-            self.expect(&token::CloseDelim(token::Paren))?;
-        }
         // Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
-        self.deduplicate_recovered_params_names(&mut fn_inputs);
+        self.deduplicate_recovered_params_names(&mut inputs);
 
         Ok(P(FnDecl {
-            inputs: fn_inputs,
+            inputs,
             output: self.parse_ret_ty(true)?,
         }))
     }
index 92b19b73e571953751c68f9016ac019bdca0170e..64c494416ff3460b808fdd31c9984e6a441ee461 100644 (file)
@@ -424,13 +424,7 @@ fn parse_item_implementation(
             } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
                 let ident = self.parse_ident().unwrap();
                 self.bump();  // `(`
-                let kw_name = if let Ok(Some(_)) = self.parse_self_parameter_with_attrs()
-                    .map_err(|mut e| e.cancel())
-                {
-                    "method"
-                } else {
-                    "function"
-                };
+                let kw_name = self.recover_first_param();
                 self.consume_block(token::Paren);
                 let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
                     self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
@@ -477,13 +471,7 @@ fn parse_item_implementation(
                 self.eat_to_tokens(&[&token::Gt]);
                 self.bump();  // `>`
                 let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
-                    if let Ok(Some(_)) = self.parse_self_parameter_with_attrs()
-                        .map_err(|mut e| e.cancel())
-                    {
-                        ("fn", "method", false)
-                    } else {
-                        ("fn", "function", false)
-                    }
+                    ("fn", self.recover_first_param(), false)
                 } else if self.check(&token::OpenDelim(token::Brace)) {
                     ("struct", "struct", false)
                 } else {
@@ -505,6 +493,16 @@ fn parse_item_implementation(
         self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
     }
 
+    fn recover_first_param(&mut self) -> &'static str {
+        match self.parse_outer_attributes()
+            .and_then(|_| self.parse_self_param())
+            .map_err(|mut e| e.cancel())
+        {
+            Ok(Some(_)) => "method",
+            _ => "function",
+        }
+    }
+
     /// This is the fall-through for parsing items.
     fn parse_macro_use_or_failure(
         &mut self,
@@ -861,9 +859,7 @@ fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
             let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
-            let decl = self.parse_fn_decl_with_self(|p| {
-                p.parse_param_general(true, false, |_| true)
-            })?;
+            let decl = self.parse_fn_decl_with_self(|_| true)?;
             generics.where_clause = self.parse_where_clause()?;
             *at_end = true;
             let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1034,15 +1030,11 @@ fn parse_trait_item_(&mut self,
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
 
-            let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
-                // This is somewhat dubious; We don't want to allow
-                // argument names to be left off if there is a
-                // definition...
-
-                // We don't allow argument names to be left off in edition 2018.
-                let is_name_required = p.token.span.rust_2018();
-                p.parse_param_general(true, false, |_| is_name_required)
-            })?;
+            // This is somewhat dubious; We don't want to allow
+            // argument names to be left off if there is a definition...
+            //
+            // We don't allow argument names to be left off in edition 2018.
+            let decl = self.parse_fn_decl_with_self(|t| t.span.rust_2018())?;
             generics.where_clause = self.parse_where_clause()?;
 
             let sig = ast::MethodSig {
index de72f1c4d4906f66749bef670870c0478b1afa35..7eb2a73a11a82c28664129ec9e465ef1a5cb13ee 100644 (file)
@@ -18,6 +18,8 @@
 /// `Expected` for function and lambda parameter patterns.
 pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
 
+const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here";
+
 /// Whether or not an or-pattern should be gated when occurring in the current context.
 #[derive(PartialEq)]
 pub enum GateOr { Yes, No }
@@ -40,7 +42,7 @@ pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
     /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
     pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P<Pat>> {
         // Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
-        let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes;
+        let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes;
         let leading_vert_span = self.prev_span;
 
         // Parse the possibly-or-pattern.
@@ -63,7 +65,7 @@ pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P<Pat>> {
     /// Parse the pattern for a function or function pointer parameter.
     /// Special recovery is provided for or-patterns and leading `|`.
     pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert("not allowed in a parameter pattern");
+        self.recover_leading_vert(None, "not allowed in a parameter pattern");
         let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
 
         if let PatKind::Or(..) = &pat.kind {
@@ -90,7 +92,7 @@ fn parse_pat_with_or(
         gate_or: GateOr,
         rc: RecoverComma,
     ) -> PResult<'a, P<Pat>> {
-        // Parse the first pattern.
+        // Parse the first pattern (`p_0`).
         let first_pat = self.parse_pat(expected)?;
         self.maybe_recover_unexpected_comma(first_pat.span, rc)?;
 
@@ -100,11 +102,12 @@ fn parse_pat_with_or(
             return Ok(first_pat)
         }
 
+        // Parse the patterns `p_1 | ... | p_n` where `n > 0`.
         let lo = first_pat.span;
         let mut pats = vec![first_pat];
-        while self.eat_or_separator() {
+        while self.eat_or_separator(Some(lo)) {
             let pat = self.parse_pat(expected).map_err(|mut err| {
-                err.span_label(lo, "while parsing this or-pattern starting here");
+                err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
             self.maybe_recover_unexpected_comma(pat.span, rc)?;
@@ -122,11 +125,15 @@ fn parse_pat_with_or(
 
     /// Eat the or-pattern `|` separator.
     /// If instead a `||` token is encountered, recover and pretend we parsed `|`.
-    fn eat_or_separator(&mut self) -> bool {
+    fn eat_or_separator(&mut self, lo: Option<Span>) -> bool {
+        if self.recover_trailing_vert(lo) {
+            return false;
+        }
+
         match self.token.kind {
             token::OrOr => {
                 // Found `||`; Recover and pretend we parsed `|`.
-                self.ban_unexpected_or_or();
+                self.ban_unexpected_or_or(lo);
                 self.bump();
                 true
             }
@@ -134,16 +141,49 @@ fn eat_or_separator(&mut self) -> bool {
         }
     }
 
+    /// Recover if `|` or `||` is the current token and we have one of the
+    /// tokens `=>`, `if`, `=`, `:`, `;`, `,`, `]`, `)`, or `}` ahead of us.
+    ///
+    /// These tokens all indicate that we reached the end of the or-pattern
+    /// list and can now reliably say that the `|` was an illegal trailing vert.
+    /// Note that there are more tokens such as `@` for which we know that the `|`
+    /// is an illegal parse. However, the user's intent is less clear in that case.
+    fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
+        let is_end_ahead = self.look_ahead(1, |token| match &token.kind {
+            token::FatArrow // e.g. `a | => 0,`.
+            | token::Ident(kw::If, false) // e.g. `a | if expr`.
+            | token::Eq // e.g. `let a | = 0`.
+            | token::Semi // e.g. `let a |;`.
+            | token::Colon // e.g. `let a | :`.
+            | token::Comma // e.g. `let (a |,)`.
+            | token::CloseDelim(token::Bracket) // e.g. `let [a | ]`.
+            | token::CloseDelim(token::Paren) // e.g. `let (a | )`.
+            | token::CloseDelim(token::Brace) => true, // e.g. `let A { f: a | }`.
+            _ => false,
+        });
+        match (is_end_ahead, &self.token.kind) {
+            (true, token::BinOp(token::Or)) | (true, token::OrOr) => {
+                self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern");
+                self.bump();
+                true
+            }
+            _ => false,
+        }
+    }
+
     /// We have parsed `||` instead of `|`. Error and suggest `|` instead.
-    fn ban_unexpected_or_or(&mut self) {
-        self.struct_span_err(self.token.span, "unexpected token `||` after pattern")
-            .span_suggestion(
-                self.token.span,
-                "use a single `|` to separate multiple alternative patterns",
-                "|".to_owned(),
-                Applicability::MachineApplicable
-            )
-            .emit();
+    fn ban_unexpected_or_or(&mut self, lo: Option<Span>) {
+        let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern");
+        err.span_suggestion(
+            self.token.span,
+            "use a single `|` to separate multiple alternative patterns",
+            "|".to_owned(),
+            Applicability::MachineApplicable
+        );
+        if let Some(lo) = lo {
+            err.span_label(lo, WHILE_PARSING_OR_MSG);
+        }
+        err.emit();
     }
 
     /// Some special error handling for the "top-level" patterns in a match arm,
@@ -198,25 +238,38 @@ fn skip_pat_list(&mut self) -> PResult<'a, ()> {
     /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`.
     /// See `parse_pat_with_or` for details on parsing or-patterns.
     fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert("only allowed in a top-level pattern");
+        self.recover_leading_vert(None, "only allowed in a top-level pattern");
         self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No)
     }
 
     /// Recover if `|` or `||` is here.
     /// The user is thinking that a leading `|` is allowed in this position.
-    fn recover_leading_vert(&mut self, ctx: &str) {
+    fn recover_leading_vert(&mut self, lo: Option<Span>, ctx: &str) {
         if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
-            let span = self.token.span;
-            let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token));
-
-            self.struct_span_err(span, &format!("a leading `|` is {}", ctx))
-                .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable)
-                .emit();
-
+            self.ban_illegal_vert(lo, "leading", ctx);
             self.bump();
         }
     }
 
+    /// A `|` or possibly `||` token shouldn't be here. Ban it.
+    fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
+        let span = self.token.span;
+        let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx));
+        err.span_suggestion(
+            span,
+            &format!("remove the `{}`", pprust::token_to_string(&self.token)),
+            String::new(),
+            Applicability::MachineApplicable,
+        );
+        if let Some(lo) = lo {
+            err.span_label(lo, WHILE_PARSING_OR_MSG);
+        }
+        if let token::OrOr = self.token.kind {
+            err.note("alternatives in or-patterns are separated with `|`, not `||`");
+        }
+        err.emit();
+    }
+
     /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
     /// allowed).
     fn parse_pat_with_range_pat(
@@ -259,7 +312,7 @@ fn parse_pat_with_range_pat(
                 self.bump();
                 self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?
             }
-            // At this point, token != &, &&, (, [
+            // At this point, token != `&`, `&&`, `(`, `[`, `..`, `..=`, or `...`.
             _ => if self.eat_keyword(kw::Underscore) {
                 // Parse _
                 PatKind::Wild
index 463ae9124ca23e2beb4432460d4646771050d816..ca823991a2e5f25d6b4291b7d857e10e6dfa0c5c 100644 (file)
@@ -114,9 +114,9 @@ pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
     pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
         let meta_ident = match self.token.kind {
             token::Interpolated(ref nt) => match **nt {
-                token::NtMeta(ref meta) => match meta.kind {
-                    ast::MetaItemKind::Word => Some(meta.path.clone()),
-                    _ => None,
+                token::NtMeta(ref item) => match item.tokens.is_empty() {
+                    true => Some(item.path.clone()),
+                    false => None,
                 },
                 _ => None,
             },
index fe3b51aa246b8cbddc326c9684ce76d07998184f..fd78a2bd53442dfe6fa3192191994db394cfb149 100644 (file)
@@ -687,7 +687,7 @@ pub enum Nonterminal {
     NtLifetime(ast::Ident),
     NtLiteral(P<ast::Expr>),
     /// Stuff inside brackets for attributes
-    NtMeta(ast::MetaItem),
+    NtMeta(ast::AttrItem),
     NtPath(ast::Path),
     NtVis(ast::Visibility),
     NtTT(TokenTree),
index 4b9c2d13f26b95b82d460c498faf7cb3a268125b..7d4ffe493d709460cf3363e3d43ab19e6925f470 100644 (file)
@@ -324,7 +324,7 @@ fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
 crate fn nonterminal_to_string(nt: &Nonterminal) -> String {
     match *nt {
         token::NtExpr(ref e)        => expr_to_string(e),
-        token::NtMeta(ref e)        => meta_item_to_string(e),
+        token::NtMeta(ref e)        => attr_item_to_string(e),
         token::NtTy(ref e)          => ty_to_string(e),
         token::NtPath(ref e)        => path_to_string(e),
         token::NtItem(ref e)        => item_to_string(e),
@@ -412,8 +412,8 @@ pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
     to_string(|s| s.print_meta_list_item(li))
 }
 
-pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
-    to_string(|s| s.print_meta_item(mi))
+fn attr_item_to_string(ai: &ast::AttrItem) -> String {
+    to_string(|s| s.print_attr_item(ai, ai.path.span))
 }
 
 pub fn attribute_to_string(attr: &ast::Attribute) -> String {
@@ -629,24 +629,28 @@ fn print_attribute_inline(&mut self, attr: &ast::Attribute,
                 ast::AttrStyle::Inner => self.word("#!["),
                 ast::AttrStyle::Outer => self.word("#["),
             }
-            self.ibox(0);
-            match attr.tokens.trees().next() {
-                Some(TokenTree::Delimited(_, delim, tts)) => {
-                    self.print_mac_common(
-                        Some(MacHeader::Path(&attr.path)), false, None, delim, tts, true, attr.span
-                    );
-                }
-                tree => {
-                    self.print_path(&attr.path, false, 0);
-                    if tree.is_some() {
-                        self.space();
-                        self.print_tts(attr.tokens.clone(), true);
-                    }
+            self.print_attr_item(&attr.item, attr.span);
+            self.word("]");
+        }
+    }
+
+    fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
+        self.ibox(0);
+        match item.tokens.trees().next() {
+            Some(TokenTree::Delimited(_, delim, tts)) => {
+                self.print_mac_common(
+                    Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span
+                );
+            }
+            tree => {
+                self.print_path(&item.path, false, 0);
+                if tree.is_some() {
+                    self.space();
+                    self.print_tts(item.tokens.clone(), true);
                 }
             }
-            self.end();
-            self.word("]");
         }
+        self.end();
     }
 
     fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
index bb8e3df3db9215fcf33b57397070b190c2b5b3dd..203c4a834899b96aaa0c0c265f2a2689c9aa1fc1 100644 (file)
@@ -1,6 +1,6 @@
 //! Attributes injected into the crate root from command line using `-Z crate-attr`.
 
-use syntax::ast::{self, AttrStyle};
+use syntax::ast::{self, AttrItem, AttrStyle};
 use syntax::attr::mk_attr;
 use syntax::panictry;
 use syntax::parse::{self, token, ParseSess};
@@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
         );
 
         let start_span = parser.token.span;
-        let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted());
+        let AttrItem { path, tokens } = panictry!(parser.parse_attr_item());
         let end_span = parser.token.span;
         if parser.token != token::Eof {
             parse_sess.span_diagnostic
index fc1daa7d9b22ad54b50dd0189758e5efc5d2c3ed..f79ad1419e0b1079764c89053ef2c563000563d7 100644 (file)
@@ -2,6 +2,7 @@
 
 use log::debug;
 use smallvec::{smallvec, SmallVec};
+use rustc_target::spec::PanicStrategy;
 use syntax::ast::{self, Ident};
 use syntax::attr;
 use syntax::entry::{self, EntryPointType};
@@ -25,6 +26,7 @@ struct Test {
 
 struct TestCtxt<'a> {
     ext_cx: ExtCtxt<'a>,
+    panic_strategy: PanicStrategy,
     def_site: Span,
     test_cases: Vec<Test>,
     reexport_test_harness_main: Option<Symbol>,
@@ -40,6 +42,9 @@ pub fn inject(
     krate: &mut ast::Crate,
     span_diagnostic: &errors::Handler,
     features: &Features,
+    panic_strategy: PanicStrategy,
+    platform_panic_strategy: PanicStrategy,
+    enable_panic_abort_tests: bool,
 ) {
     // Check for #![reexport_test_harness_main = "some_name"] which gives the
     // main test function the name `some_name` without hygiene. This needs to be
@@ -53,8 +58,22 @@ pub fn inject(
     let test_runner = get_test_runner(span_diagnostic, &krate);
 
     if should_test {
+        let panic_strategy = match (panic_strategy, enable_panic_abort_tests) {
+            (PanicStrategy::Abort, true) =>
+                PanicStrategy::Abort,
+            (PanicStrategy::Abort, false) if panic_strategy == platform_panic_strategy => {
+                // Silently allow compiling with panic=abort on these platforms,
+                // but with old behavior (abort if a test fails).
+                PanicStrategy::Unwind
+            }
+            (PanicStrategy::Abort, false) => {
+                span_diagnostic.err("building tests with panic=abort is not yet supported");
+                PanicStrategy::Unwind
+            }
+            (PanicStrategy::Unwind, _) => PanicStrategy::Unwind,
+        };
         generate_test_harness(sess, resolver, reexport_test_harness_main,
-                              krate, features, test_runner)
+                              krate, features, panic_strategy, test_runner)
     }
 }
 
@@ -183,6 +202,7 @@ fn generate_test_harness(sess: &ParseSess,
                          reexport_test_harness_main: Option<Symbol>,
                          krate: &mut ast::Crate,
                          features: &Features,
+                         panic_strategy: PanicStrategy,
                          test_runner: Option<ast::Path>) {
     let mut econfig = ExpansionConfig::default("test".to_string());
     econfig.features = Some(features);
@@ -203,6 +223,7 @@ fn generate_test_harness(sess: &ParseSess,
 
     let cx = TestCtxt {
         ext_cx,
+        panic_strategy,
         def_site,
         test_cases: Vec::new(),
         reexport_test_harness_main,
@@ -248,9 +269,14 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
     let ecx = &cx.ext_cx;
     let test_id = Ident::new(sym::test, sp);
 
+    let runner_name = match cx.panic_strategy {
+        PanicStrategy::Unwind => "test_main_static",
+        PanicStrategy::Abort => "test_main_static_abort",
+    };
+
     // test::test_main_static(...)
     let mut test_runner = cx.test_runner.clone().unwrap_or(
-        ecx.path(sp, vec![test_id, ecx.ident_of("test_main_static", sp)]));
+        ecx.path(sp, vec![test_id, ecx.ident_of(runner_name, sp)]));
 
     test_runner.span = sp;
 
index bc13d2a1611323a6574659387e2445ddbe15f1c7..378f7a955a36fb6edd0ae80ca3cea99f18e8688f 100644 (file)
@@ -13,6 +13,7 @@ doctest = false
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_index = { path = "../librustc_index" }
 arena = { path = "../libarena" }
 scoped-tls = "1.0"
 unicode-width = "0.1.4"
index 44a34070deccd9ac39fb760e5a6f2b30b3cd7531..1769135e7f21a1b6948df0e79dfdfe2977f320b5 100644 (file)
@@ -4,8 +4,7 @@
 
 use arena::DroplessArena;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::newtype_index;
+use rustc_index::vec::Idx;
 use rustc_macros::symbols;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_serialize::{UseSpecializedDecodable, UseSpecializedEncodable};
@@ -897,15 +896,15 @@ fn default_decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
 /// ```
 /// Internally, a symbol is implemented as an index, and all operations
 /// (including hashing, equality, and ordering) operate on that index. The use
-/// of `newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
-/// because `newtype_index!` reserves the last 256 values for tagging purposes.
+/// of `rustc_index::newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
+/// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes.
 ///
-/// Note that `Symbol` cannot directly be a `newtype_index!` because it
+/// Note that `Symbol` cannot directly be a `rustc_index::newtype_index!` because it
 /// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Symbol(SymbolIndex);
 
-newtype_index! {
+rustc_index::newtype_index! {
     pub struct SymbolIndex { .. }
 }
 
index e97cda76d23180e33e5f35b5022a26231a787a49..dd202fb3ab6faa0536b4843d7c4d2a6f9b8855f6 100644 (file)
@@ -22,3 +22,12 @@ fn write_result(
     ) -> io::Result<()>;
     fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool>;
 }
+
+pub(crate) fn write_stderr_delimiter(test_output: &mut Vec<u8>, test_name: &TestName) {
+    match test_output.last() {
+        Some(b'\n') => (),
+        Some(_) => test_output.push(b'\n'),
+        None => (),
+    }
+    write!(test_output, "---- {} stderr ----\n", test_name).unwrap();
+}
index bcda5384204d8de3caa0db0dc0c9d5396f5edb4f..f04d289c4ef332227b1e9ef2ef333cb8ed820cbf 100644 (file)
@@ -21,7 +21,8 @@
 #![unstable(feature = "test", issue = "50297")]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
 #![feature(asm)]
-#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc, rustc_private))]
+#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))]
+#![feature(rustc_private)]
 #![feature(nll)]
 #![feature(set_stdio)]
 #![feature(panic_unwind)]
 extern crate libc;
 use term;
 
-// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind
-//                on aarch64-pc-windows-msvc, or thumbv7a-pc-windows-msvc
-//                so we don't link libtest against libunwind (for the time being)
-//                even though it means that libtest won't be fully functional on
-//                these platforms.
-//
-// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
-#[cfg(not(all(windows, any(target_arch = "aarch64", target_arch = "arm"))))]
-extern crate panic_unwind;
-
 pub use self::ColorConfig::*;
 use self::NamePadding::*;
 use self::OutputLocation::*;
 use std::fs::File;
 use std::io;
 use std::io::prelude::*;
-use std::panic::{catch_unwind, AssertUnwindSafe};
+use std::panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo};
 use std::path::PathBuf;
 use std::process;
-use std::process::Termination;
+use std::process::{ExitStatus, Command, Termination};
 use std::sync::mpsc::{channel, Sender};
 use std::sync::{Arc, Mutex};
 use std::thread;
 const TEST_WARN_TIMEOUT_S: u64 = 60;
 const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
 
+const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE";
+
+// Return codes for secondary process.
+// Start somewhere other than 0 so we know the return code means what we think
+// it means.
+const TR_OK: i32 = 50;
+const TR_FAILED: i32 = 51;
+
 // to be used by rustc to compile tests in libtest
 pub mod test {
     pub use crate::{
         assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
-        Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic,
-        StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts,
-        TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk,
+        Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, RunStrategy,
+        ShouldPanic, StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName,
+        TestOpts, TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk,
     };
 }
 
@@ -257,12 +256,14 @@ pub fn new(value: f64, noise: f64) -> Metric {
 #[derive(Copy, Clone, Debug)]
 pub struct Options {
     display_output: bool,
+    panic_abort: bool,
 }
 
 impl Options {
     pub fn new() -> Options {
         Options {
             display_output: false,
+            panic_abort: false,
         }
     }
 
@@ -270,6 +271,11 @@ pub fn display_output(mut self, display_output: bool) -> Options {
         self.display_output = display_output;
         self
     }
+
+    pub fn panic_abort(mut self, panic_abort: bool) -> Options {
+        self.panic_abort = panic_abort;
+        self
+    }
 }
 
 // The default console test runner. It accepts the command line
@@ -303,32 +309,66 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
     }
 }
 
-// A variant optimized for invocation with a static test vector.
-// This will panic (intentionally) when fed any dynamic tests, because
-// it is copying the static values out into a dynamic vector and cannot
-// copy dynamic values. It is doing this because from this point on
-// a Vec<TestDescAndFn> is used in order to effect ownership-transfer
-// semantics into parallel test runners, which in turn requires a Vec<>
-// rather than a &[].
+/// A variant optimized for invocation with a static test vector.
+/// This will panic (intentionally) when fed any dynamic tests.
+///
+/// This is the entry point for the main function generated by `rustc --test`
+/// when panic=unwind.
 pub fn test_main_static(tests: &[&TestDescAndFn]) {
     let args = env::args().collect::<Vec<_>>();
-    let owned_tests = tests
-        .iter()
-        .map(|t| match t.testfn {
-            StaticTestFn(f) => TestDescAndFn {
-                testfn: StaticTestFn(f),
-                desc: t.desc.clone(),
-            },
-            StaticBenchFn(f) => TestDescAndFn {
-                testfn: StaticBenchFn(f),
-                desc: t.desc.clone(),
-            },
-            _ => panic!("non-static tests passed to test::test_main_static"),
-        })
-        .collect();
+    let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect();
     test_main(&args, owned_tests, None)
 }
 
+/// A variant optimized for invocation with a static test vector.
+/// This will panic (intentionally) when fed any dynamic tests.
+///
+/// Runs tests in panic=abort mode, which involves spawning subprocesses for
+/// tests.
+///
+/// This is the entry point for the main function generated by `rustc --test`
+/// when panic=abort.
+pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
+    // If we're being run in SpawnedSecondary mode, run the test here. run_test
+    // will then exit the process.
+    if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) {
+        let test = tests
+            .iter()
+            .filter(|test| test.desc.name.as_slice() == name)
+            .map(make_owned_test)
+            .next()
+            .expect("couldn't find a test with the provided name");
+        let TestDescAndFn { desc, testfn } = test;
+        let testfn = match testfn {
+            StaticTestFn(f) => f,
+            _ => panic!("only static tests are supported"),
+        };
+        run_test_in_spawned_subprocess(desc, Box::new(testfn));
+    }
+
+    let args = env::args().collect::<Vec<_>>();
+    let owned_tests: Vec<_> = tests.iter().map(make_owned_test).collect();
+    test_main(&args, owned_tests, Some(Options::new().panic_abort(true)))
+}
+
+/// Clones static values for putting into a dynamic vector, which test_main()
+/// needs to hand out ownership of tests to parallel test runners.
+///
+/// This will panic when fed any dynamic tests, because they cannot be cloned.
+fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn {
+    match test.testfn {
+        StaticTestFn(f) => TestDescAndFn {
+            testfn: StaticTestFn(f),
+            desc: test.desc.clone(),
+        },
+        StaticBenchFn(f) => TestDescAndFn {
+            testfn: StaticBenchFn(f),
+            desc: test.desc.clone(),
+        },
+        _ => panic!("non-static tests passed to test::test_main_static"),
+    }
+}
+
 /// Invoked when unit tests terminate. Should panic if the unit
 /// Tests is considered a failure. By default, invokes `report()`
 /// and checks for a `0` result.
@@ -1062,6 +1102,18 @@ fn flush(&mut self) -> io::Result<()> {
     }
 }
 
+#[derive(Clone, Copy)]
+pub enum RunStrategy {
+    /// Runs the test in the current process, and sends the result back over the
+    /// supplied channel.
+    InProcess,
+
+    /// Spawns a subprocess to run the test, and sends the result back over the
+    /// supplied channel. Requires argv[0] to exist and point to the binary
+    /// that's currently running.
+    SpawnPrimary,
+}
+
 pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
 where
     F: FnMut(TestEvent) -> io::Result<()>,
@@ -1109,6 +1161,11 @@ pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F)
     let mut pending = 0;
 
     let (tx, rx) = channel::<MonitorMsg>();
+    let run_strategy = if opts.options.panic_abort {
+        RunStrategy::SpawnPrimary
+    } else {
+        RunStrategy::InProcess
+    };
 
     let mut running_tests: TestMap = HashMap::default();
 
@@ -1145,7 +1202,7 @@ fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
         while !remaining.is_empty() {
             let test = remaining.pop().unwrap();
             callback(TeWait(test.desc.clone()))?;
-            run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::No);
+            run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No);
             let (test, result, exec_time, stdout) = rx.recv().unwrap();
             callback(TeResult(test, result, exec_time, stdout))?;
         }
@@ -1156,7 +1213,7 @@ fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
                 let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
                 running_tests.insert(test.desc.clone(), timeout);
                 callback(TeWait(test.desc.clone()))?; //here no pad
-                run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::Yes);
+                run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes);
                 pending += 1;
             }
 
@@ -1188,7 +1245,7 @@ fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
         // All benchmarks run at the end, in serial.
         for b in filtered_benchs {
             callback(TeWait(b.desc.clone()))?;
-            run_test(opts, false, b, tx.clone(), Concurrent::No);
+            run_test(opts, false, b, run_strategy, tx.clone(), Concurrent::No);
             let (test, result, exec_time, stdout) = rx.recv().unwrap();
             callback(TeResult(test, result, exec_time, stdout))?;
         }
@@ -1415,64 +1472,38 @@ pub fn run_test(
     opts: &TestOpts,
     force_ignore: bool,
     test: TestDescAndFn,
+    strategy: RunStrategy,
     monitor_ch: Sender<MonitorMsg>,
     concurrency: Concurrent,
 ) {
     let TestDescAndFn { desc, testfn } = test;
 
-    let ignore_because_panic_abort = cfg!(target_arch = "wasm32")
+    let ignore_because_no_process_support = cfg!(target_arch = "wasm32")
         && !cfg!(target_os = "emscripten")
         && desc.should_panic != ShouldPanic::No;
 
-    if force_ignore || desc.ignore || ignore_because_panic_abort {
+    if force_ignore || desc.ignore || ignore_because_no_process_support {
         monitor_ch.send((desc, TrIgnored, None, Vec::new())).unwrap();
         return;
     }
 
     fn run_test_inner(
         desc: TestDesc,
-        monitor_ch: Sender<MonitorMsg>,
         nocapture: bool,
         report_time: bool,
+        strategy: RunStrategy,
+        monitor_ch: Sender<MonitorMsg>,
         testfn: Box<dyn FnOnce() + Send>,
         concurrency: Concurrent,
     ) {
-        // Buffer for capturing standard I/O
-        let data = Arc::new(Mutex::new(Vec::new()));
-        let data2 = data.clone();
-
         let name = desc.name.clone();
-        let runtest = move || {
-            let oldio = if !nocapture {
-                Some((
-                    io::set_print(Some(Box::new(Sink(data2.clone())))),
-                    io::set_panic(Some(Box::new(Sink(data2)))),
-                ))
-            } else {
-                None
-            };
-
-            let start = if report_time {
-                Some(Instant::now())
-            } else {
-                None
-            };
-            let result = catch_unwind(AssertUnwindSafe(testfn));
-            let exec_time = start.map(|start| {
-                let duration = start.elapsed();
-                TestExecTime(duration)
-            });
-
-            if let Some((printio, panicio)) = oldio {
-                io::set_print(printio);
-                io::set_panic(panicio);
-            };
 
-            let test_result = calc_result(&desc, result);
-            let stdout = data.lock().unwrap().to_vec();
-            monitor_ch
-                .send((desc.clone(), test_result, exec_time, stdout))
-                .unwrap();
+        let runtest = move || {
+            match strategy {
+                RunStrategy::InProcess =>
+                    run_test_in_process(desc, nocapture, report_time, testfn, monitor_ch),
+                RunStrategy::SpawnPrimary => spawn_test_subprocess(desc, report_time, monitor_ch),
+            }
         };
 
         // If the platform is single-threaded we're just going to run
@@ -1489,31 +1520,38 @@ fn run_test_inner(
 
     match testfn {
         DynBenchFn(bencher) => {
+            // Benchmarks aren't expected to panic, so we run them all in-process.
             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
                 bencher.run(harness)
             });
         }
         StaticBenchFn(benchfn) => {
+            // Benchmarks aren't expected to panic, so we run them all in-process.
             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
                 (benchfn.clone())(harness)
             });
         }
         DynTestFn(f) => {
-            let cb = move || __rust_begin_short_backtrace(f);
+            match strategy {
+                RunStrategy::InProcess => (),
+                _ => panic!("Cannot run dynamic test fn out-of-process"),
+            };
             run_test_inner(
                 desc,
-                monitor_ch,
                 opts.nocapture,
                 opts.report_time,
-                Box::new(cb),
-                concurrency,
-            )
+                strategy,
+                monitor_ch,
+                Box::new(move || __rust_begin_short_backtrace(f)),
+                concurrency
+            );
         }
         StaticTestFn(f) => run_test_inner(
             desc,
-            monitor_ch,
             opts.nocapture,
             opts.report_time,
+            strategy,
+            monitor_ch,
             Box::new(move || __rust_begin_short_backtrace(f)),
             concurrency,
         ),
@@ -1526,7 +1564,9 @@ fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
     f()
 }
 
-fn calc_result(desc: &TestDesc, task_result: Result<(), Box<dyn Any + Send>>) -> TestResult {
+fn calc_result<'a>(desc: &TestDesc,
+                   task_result: Result<(), &'a (dyn Any + 'static + Send)>)
+-> TestResult {
     match (&desc.should_panic, task_result) {
         (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk,
         (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
@@ -1552,6 +1592,150 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box<dyn Any + Send>>) ->
     }
 }
 
+fn get_result_from_exit_code(desc: &TestDesc, code: i32) -> TestResult {
+    match (desc.allow_fail, code) {
+        (_, TR_OK) => TrOk,
+        (true, TR_FAILED) => TrAllowedFail,
+        (false, TR_FAILED) => TrFailed,
+        (_, _) => TrFailedMsg(format!("got unexpected return code {}", code)),
+    }
+}
+
+fn run_test_in_process(desc: TestDesc,
+                       nocapture: bool,
+                       report_time: bool,
+                       testfn: Box<dyn FnOnce() + Send>,
+                       monitor_ch: Sender<MonitorMsg>) {
+    // Buffer for capturing standard I/O
+    let data = Arc::new(Mutex::new(Vec::new()));
+
+    let oldio = if !nocapture {
+        Some((
+            io::set_print(Some(Box::new(Sink(data.clone())))),
+            io::set_panic(Some(Box::new(Sink(data.clone())))),
+        ))
+    } else {
+        None
+    };
+
+    let start = if report_time {
+        Some(Instant::now())
+    } else {
+        None
+    };
+    let result = catch_unwind(AssertUnwindSafe(testfn));
+    let exec_time = start.map(|start| {
+        let duration = start.elapsed();
+        TestExecTime(duration)
+    });
+
+    if let Some((printio, panicio)) = oldio {
+        io::set_print(printio);
+        io::set_panic(panicio);
+    }
+
+    let test_result = match result {
+        Ok(()) => calc_result(&desc, Ok(())),
+        Err(e) => calc_result(&desc, Err(e.as_ref())),
+    };
+    let stdout = data.lock().unwrap().to_vec();
+    monitor_ch.send((desc.clone(), test_result, exec_time, stdout)).unwrap();
+}
+
+fn spawn_test_subprocess(desc: TestDesc, report_time: bool, monitor_ch: Sender<MonitorMsg>) {
+    let (result, test_output, exec_time) = (|| {
+        let args = env::args().collect::<Vec<_>>();
+        let current_exe = &args[0];
+
+        let start = if report_time {
+            Some(Instant::now())
+        } else {
+            None
+        };
+        let output = match Command::new(current_exe)
+            .env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice())
+            .output() {
+                Ok(out) => out,
+                Err(e) => {
+                    let err = format!("Failed to spawn {} as child for test: {:?}", args[0], e);
+                    return (TrFailed, err.into_bytes(), None);
+                }
+            };
+        let exec_time = start.map(|start| {
+            let duration = start.elapsed();
+            TestExecTime(duration)
+        });
+
+        let std::process::Output { stdout, stderr, status } = output;
+        let mut test_output = stdout;
+        formatters::write_stderr_delimiter(&mut test_output, &desc.name);
+        test_output.extend_from_slice(&stderr);
+
+        let result = match (|| -> Result<TestResult, String> {
+            let exit_code = get_exit_code(status)?;
+            Ok(get_result_from_exit_code(&desc, exit_code))
+        })() {
+            Ok(r) => r,
+            Err(e) => {
+                write!(&mut test_output, "Unexpected error: {}", e).unwrap();
+                TrFailed
+            }
+        };
+
+        (result, test_output, exec_time)
+    })();
+
+    monitor_ch.send((desc.clone(), result, exec_time, test_output)).unwrap();
+}
+
+fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box<dyn FnOnce() + Send>) -> ! {
+    let builtin_panic_hook = panic::take_hook();
+    let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| {
+        let test_result = match panic_info {
+            Some(info) => calc_result(&desc, Err(info.payload())),
+            None => calc_result(&desc, Ok(())),
+        };
+
+        // We don't support serializing TrFailedMsg, so just
+        // print the message out to stderr.
+        if let TrFailedMsg(msg) = &test_result {
+            eprintln!("{}", msg);
+        }
+
+        if let Some(info) = panic_info {
+            builtin_panic_hook(info);
+        }
+
+        if let TrOk = test_result {
+            process::exit(TR_OK);
+        } else {
+            process::exit(TR_FAILED);
+        }
+    });
+    let record_result2 = record_result.clone();
+    panic::set_hook(Box::new(move |info| record_result2(Some(&info))));
+    testfn();
+    record_result(None);
+    unreachable!("panic=abort callback should have exited the process")
+}
+
+#[cfg(not(unix))]
+fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
+    status.code().ok_or("received no exit code from child process".into())
+}
+
+#[cfg(unix)]
+fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
+    use std::os::unix::process::ExitStatusExt;
+    match status.code() {
+        Some(code) => Ok(code),
+        None => match status.signal() {
+            Some(signal) => Err(format!("child process exited with signal {}", signal)),
+            None => Err("child process exited with unknown signal".into()),
+        }
+    }
+}
+
 #[derive(Clone, PartialEq)]
 pub struct MetricMap(BTreeMap<String, Metric>);
 
@@ -1700,7 +1884,9 @@ pub fn iter<T, F>(inner: &mut F) -> stats::Summary
 }
 
 pub mod bench {
-    use super::{BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult};
+    use super::{
+        BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult
+    };
     use crate::stats;
     use std::cmp;
     use std::io;
@@ -1718,12 +1904,10 @@ pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: b
         };
 
         let data = Arc::new(Mutex::new(Vec::new()));
-        let data2 = data.clone();
-
         let oldio = if !nocapture {
             Some((
-                io::set_print(Some(Box::new(Sink(data2.clone())))),
-                io::set_panic(Some(Box::new(Sink(data2)))),
+                io::set_print(Some(Box::new(Sink(data.clone())))),
+                io::set_panic(Some(Box::new(Sink(data.clone())))),
             ))
         } else {
             None
@@ -1734,7 +1918,7 @@ pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: b
         if let Some((printio, panicio)) = oldio {
             io::set_print(printio);
             io::set_panic(panicio);
-        };
+        }
 
         let test_result = match result {
             //bs.bench(f) {
index 38ec7bd70930c44fd77f7efb7640e6f4d51a1963..b95fb5df710d35873be882a3900c6b8c4dd97ac7 100644 (file)
@@ -1,7 +1,7 @@
 use super::*;
 
 use crate::test::{
-    filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored,
+    filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, RunStrategy,
     ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailedMsg,
     TrIgnored, TrOk,
 };
@@ -67,7 +67,7 @@ fn f() {
         testfn: DynTestFn(Box::new(f)),
     };
     let (tx, rx) = channel();
-    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
     let (_, res, _, _) = rx.recv().unwrap();
     assert!(res != TrOk);
 }
@@ -85,7 +85,7 @@ fn f() {}
         testfn: DynTestFn(Box::new(f)),
     };
     let (tx, rx) = channel();
-    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
     let (_, res, _, _) = rx.recv().unwrap();
     assert!(res == TrIgnored);
 }
@@ -105,7 +105,7 @@ fn f() {
         testfn: DynTestFn(Box::new(f)),
     };
     let (tx, rx) = channel();
-    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
     let (_, res, _, _) = rx.recv().unwrap();
     assert!(res == TrOk);
 }
@@ -125,7 +125,7 @@ fn f() {
         testfn: DynTestFn(Box::new(f)),
     };
     let (tx, rx) = channel();
-    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
     let (_, res, _, _) = rx.recv().unwrap();
     assert!(res == TrOk);
 }
@@ -147,7 +147,7 @@ fn f() {
         testfn: DynTestFn(Box::new(f)),
     };
     let (tx, rx) = channel();
-    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
     let (_, res, _, _) = rx.recv().unwrap();
     assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
 }
@@ -165,7 +165,7 @@ fn f() {}
         testfn: DynTestFn(Box::new(f)),
     };
     let (tx, rx) = channel();
-    run_test(&TestOpts::new(), false, desc, tx, Concurrent::No);
+    run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
     let (_, res, _, _) = rx.recv().unwrap();
     assert!(res == TrFailedMsg("test did not panic as expected".to_string()));
 }
@@ -186,7 +186,7 @@ fn f() {}
         ..TestOpts::new()
     };
     let (tx, rx) = channel();
-    run_test(&test_opts, false, desc, tx, Concurrent::No);
+    run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No);
     let (_, _, exec_time, _) = rx.recv().unwrap();
     exec_time
 }
index 336b584768fadb7e9464c392845c27a35490ff96..fe68b394e5a5cf2c2f9dc01e3a4391d0a2f5523c 100644 (file)
@@ -2,10 +2,10 @@
 
 #![feature(rustc_private)]
 
-extern crate rustc_data_structures;
+extern crate rustc_index;
 extern crate serialize as rustc_serialize;
 
-use rustc_data_structures::{newtype_index, indexed_vec::Idx};
+use rustc_index::{newtype_index, vec::Idx};
 
 newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA });
 
diff --git a/src/test/ui/abi/macros/macros-in-extern.rs b/src/test/ui/abi/macros/macros-in-extern.rs
deleted file mode 100644 (file)
index bba8b15..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// ignore-wasm32
-
-#![feature(decl_macro)]
-
-macro_rules! returns_isize(
-    ($ident:ident) => (
-        fn $ident() -> isize;
-    )
-);
-
-macro takes_u32_returns_u32($ident:ident) {
-    fn $ident (arg: u32) -> u32;
-}
-
-macro_rules! emits_nothing(
-    () => ()
-);
-
-fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 0isize);
-    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
-}
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    returns_isize!(rust_get_test_int);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    emits_nothing!();
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-}
diff --git a/src/test/ui/abi/macros/macros-in-extern.stderr b/src/test/ui/abi/macros/macros-in-extern.stderr
deleted file mode 100644 (file)
index 6ee33f4..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:26:5
-   |
-LL |     returns_isize!(rust_get_test_int);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:28:5
-   |
-LL |     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:30:5
-   |
-LL |     emits_nothing!();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs b/src/test/ui/abi/proc-macro/auxiliary/test-macros.rs
deleted file mode 100644 (file)
index 27efa44..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-// force-host
-// no-prefer-dynamic
-
-// Proc macros commonly used by tests.
-// `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros.
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-use proc_macro::TokenStream;
-
-// Macro that return empty token stream.
-
-#[proc_macro]
-pub fn empty(_: TokenStream) -> TokenStream {
-    TokenStream::new()
-}
-
-#[proc_macro_attribute]
-pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream {
-    TokenStream::new()
-}
-
-#[proc_macro_derive(Empty, attributes(empty_helper))]
-pub fn empty_derive(_: TokenStream) -> TokenStream {
-    TokenStream::new()
-}
-
-// Macro that panics.
-
-#[proc_macro]
-pub fn panic_bang(_: TokenStream) -> TokenStream {
-    panic!("panic-bang");
-}
-
-#[proc_macro_attribute]
-pub fn panic_attr(_: TokenStream, _: TokenStream) -> TokenStream {
-    panic!("panic-attr");
-}
-
-#[proc_macro_derive(Panic, attributes(panic_helper))]
-pub fn panic_derive(_: TokenStream) -> TokenStream {
-    panic!("panic-derive");
-}
-
-// Macros that return the input stream.
-
-#[proc_macro]
-pub fn identity(input: TokenStream) -> TokenStream {
-    input
-}
-
-#[proc_macro_attribute]
-pub fn identity_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    input
-}
-
-#[proc_macro_derive(Identity, attributes(identity_helper))]
-pub fn identity_derive(input: TokenStream) -> TokenStream {
-    input
-}
-
-// Macros that iterate and re-collect the input stream.
-
-#[proc_macro]
-pub fn recollect(input: TokenStream) -> TokenStream {
-    input.into_iter().collect()
-}
-
-#[proc_macro_attribute]
-pub fn recollect_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    input.into_iter().collect()
-}
-
-#[proc_macro_derive(Recollect, attributes(recollect_helper))]
-pub fn recollect_derive(input: TokenStream) -> TokenStream {
-    input.into_iter().collect()
-}
-
-// Macros that print their input in the original and re-collected forms (if they differ).
-
-fn print_helper(input: TokenStream, kind: &str) -> TokenStream {
-    let input_display = format!("{}", input);
-    let input_debug = format!("{:#?}", input);
-    let recollected = input.into_iter().collect();
-    let recollected_display = format!("{}", recollected);
-    let recollected_debug = format!("{:#?}", recollected);
-    println!("PRINT-{} INPUT (DISPLAY): {}", kind, input_display);
-    if recollected_display != input_display {
-        println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display);
-    }
-    println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug);
-    if recollected_debug != input_debug {
-        println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug);
-    }
-    recollected
-}
-
-#[proc_macro]
-pub fn print_bang(input: TokenStream) -> TokenStream {
-    print_helper(input, "BANG")
-}
-
-#[proc_macro_attribute]
-pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream {
-    print_helper(input, "ATTR")
-}
-
-#[proc_macro_derive(Print, attributes(print_helper))]
-pub fn print_derive(input: TokenStream) -> TokenStream {
-    print_helper(input, "DERIVE")
-}
diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.rs b/src/test/ui/abi/proc-macro/macros-in-extern.rs
deleted file mode 100644 (file)
index 0477b5c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// aux-build:test-macros.rs
-// ignore-wasm32
-
-#[macro_use]
-extern crate test_macros;
-
-fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 0isize);
-    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
-}
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    #[empty_attr]
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    fn some_definitely_unknown_symbol_which_should_be_removed();
-
-    #[identity_attr]
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    fn rust_get_test_int() -> isize;
-
-    identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-}
diff --git a/src/test/ui/abi/proc-macro/macros-in-extern.stderr b/src/test/ui/abi/proc-macro/macros-in-extern.stderr
deleted file mode 100644 (file)
index 6049c2a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:14:5
-   |
-LL |     #[empty_attr]
-   |     ^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:18:5
-   |
-LL |     #[identity_attr]
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/macros-in-extern.rs:22:5
-   |
-LL |     identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index e466ad69f721c244ace871bd989582448e7633b8..6381bb2d588770c275710e9e3ae855da5af1087c 100644 (file)
@@ -57,7 +57,7 @@ fn main() {
     // check that macro expanded code works
 
     macro_rules! if_cfg {
-        ($cfg:meta $ib:block else $eb:block) => {
+        ($cfg:meta? $ib:block else $eb:block) => {
             {
                 let r;
                 #[cfg($cfg)]
@@ -69,7 +69,7 @@ macro_rules! if_cfg {
         }
     }
 
-    let n = if_cfg!(unset {
+    let n = if_cfg!(unset? {
         413
     } else {
         612
index a13c217483d5dea7e2028c1f4bdc91830b192025..7d7ecbd1a26a579eaeb289f7a994f2bedcdc0b6d 100644 (file)
@@ -108,5 +108,5 @@ LL |     let y = { static x: Box<isize> = box 3; x };
 
 error: aborting due to 17 previous errors
 
-Some errors have detailed explanations: E0010, E0015, E0019, E0507.
+Some errors have detailed explanations: E0010, E0015, E0019, E0493, E0507.
 For more information about an error, try `rustc --explain E0010`.
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.rs b/src/test/ui/const-generics/slice-const-param-mismatch.rs
new file mode 100644 (file)
index 0000000..73c75ae
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct ConstString<const T: &'static str>;
+struct ConstBytes<const T: &'static [u8]>;
+
+pub fn main() {
+    let _: ConstString<"Hello"> = ConstString::<"Hello">;
+    let _: ConstString<"Hello"> = ConstString::<"World">; //~ ERROR mismatched types
+    let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↦">;
+    let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //~ ERROR mismatched types
+    let _: ConstBytes<b"AAA"> = ConstBytes::<{&[0x41, 0x41, 0x41]}>;
+    let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.stderr
new file mode 100644 (file)
index 0000000..72369ab
--- /dev/null
@@ -0,0 +1,38 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/slice-const-param-mismatch.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/slice-const-param-mismatch.rs:9:35
+   |
+LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
+   |
+   = note: expected type `ConstString<>`
+              found type `ConstString<>`
+
+error[E0308]: mismatched types
+  --> $DIR/slice-const-param-mismatch.rs:11:33
+   |
+LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
+   |                                  ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
+   |
+   = note: expected type `ConstString<>`
+              found type `ConstString<>`
+
+error[E0308]: mismatched types
+  --> $DIR/slice-const-param-mismatch.rs:13:33
+   |
+LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
+   |                                 ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
+   |
+   = note: expected type `ConstBytes<>`
+              found type `ConstBytes<>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/slice-const-param.rs b/src/test/ui/const-generics/slice-const-param.rs
new file mode 100644 (file)
index 0000000..2629caa
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+pub fn function_with_str<const STRING: &'static str>() -> &'static str {
+    STRING
+}
+
+pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
+    BYTES
+}
+
+pub fn main() {
+    assert_eq!(function_with_str::<"Rust">(), "Rust");
+    assert_eq!(function_with_str::<"ℇ㇈↦">(), "ℇ㇈↦");
+    assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
+    assert_eq!(function_with_bytes::<{&[0x41, 0x41, 0x41, 0x41]}>(), b"AAAA");
+}
diff --git a/src/test/ui/const-generics/slice-const-param.stderr b/src/test/ui/const-generics/slice-const-param.stderr
new file mode 100644 (file)
index 0000000..79214a3
--- /dev/null
@@ -0,0 +1,8 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/slice-const-param.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
index 0a6a222ae2963a30ea5cb396edebb294dbe53d71..4753222a7c07d816fb5f49190e58dcdb891b02fb 100644 (file)
@@ -24,3 +24,4 @@ LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/issue-64662.rs b/src/test/ui/consts/issue-64662.rs
new file mode 100644 (file)
index 0000000..e3a8c85
--- /dev/null
@@ -0,0 +1,10 @@
+enum Foo {
+    A = foo(), //~ ERROR: type annotations needed
+    B = foo(), //~ ERROR: type annotations needed
+}
+
+const fn foo<T>() -> isize {
+    0
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-64662.stderr b/src/test/ui/consts/issue-64662.stderr
new file mode 100644 (file)
index 0000000..b81daae
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-64662.rs:2:9
+   |
+LL |     A = foo(),
+   |         ^^^ cannot infer type for `T`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-64662.rs:3:9
+   |
+LL |     B = foo(),
+   |         ^^^ cannot infer type for `T`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
index 7919cfe987cfc5c149d875a90406cfab3776679c..3158b6284db94761732509b56d93137268249d9f 100644 (file)
@@ -324,5 +324,5 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
 
 error: aborting due to 37 previous errors
 
-Some errors have detailed explanations: E0515, E0723.
-For more information about an error, try `rustc --explain E0515`.
+Some errors have detailed explanations: E0493, E0515, E0723.
+For more information about an error, try `rustc --explain E0493`.
index 5bc7b70638c80f372c9160de20d3a292dba8a269..37016664ac58f38c913b3d1dbd36cf8ddd243c99 100644 (file)
@@ -6,3 +6,4 @@ LL |     const F: u32 = (U::X, 42).1;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0493`.
index 7ff68a1038b1c103ecc324a31028d0354129cbb8..15afa78b140d5eb2aa09e7f660fe2fd3304392a3 100644 (file)
@@ -54,5 +54,5 @@ LL | #[deprecated(since = "a", since = "b", note = "c")]
 
 error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0538, E0541, E0565.
+Some errors have detailed explanations: E0538, E0541, E0550, E0565.
 For more information about an error, try `rustc --explain E0538`.
index b9681db87b67ea5c494ccfb5e384d8e88b3d18dd..97121575527168bada13f139fba18282b884ec43 100644 (file)
@@ -1,6 +1,9 @@
 error[E0423]: expected value, found struct `Empty1`
   --> $DIR/empty-struct-braces-expr.rs:15:14
    |
+LL | struct Empty1 {}
+   | ---------------- `Empty1` defined here
+...
 LL |     let e1 = Empty1;
    |              ^^^^^^
    |              |
@@ -10,6 +13,9 @@ LL |     let e1 = Empty1;
 error[E0423]: expected function, found struct `Empty1`
   --> $DIR/empty-struct-braces-expr.rs:16:14
    |
+LL | struct Empty1 {}
+   | ---------------- `Empty1` defined here
+...
 LL |     let e1 = Empty1();
    |              ^^^^^^
    |              |
@@ -19,12 +25,18 @@ LL |     let e1 = Empty1();
 error[E0423]: expected value, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-expr.rs:17:14
    |
+LL |     Empty3 {}
+   |     --------- `E::Empty3` defined here
+...
 LL |     let e3 = E::Empty3;
    |              ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
 
 error[E0423]: expected function, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-expr.rs:18:14
    |
+LL |     Empty3 {}
+   |     --------- `E::Empty3` defined here
+...
 LL |     let e3 = E::Empty3();
    |              ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
 
index 6c361c703440c1a15cf30f747a6f09c7c9b6094b..271e811a2fd65738ce8f8b96a89074d991b4ae30 100644 (file)
@@ -1,6 +1,9 @@
 error[E0532]: expected unit struct/variant or constant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-1.rs:24:9
    |
+LL |     Empty3 {}
+   |     --------- `E::Empty3` defined here
+...
 LL |         E::Empty3 => ()
    |         ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
 
index 12047b5880c3e6f334977d178cbe8d0efb4eec4c..33524737888944217b98933d79e23078d7e431ef 100644 (file)
@@ -1,6 +1,9 @@
 error[E0532]: expected tuple struct/variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-pat-2.rs:15:9
    |
+LL | struct Empty1 {}
+   | ---------------- `Empty1` defined here
+...
 LL |         Empty1() => ()
    |         ^^^^^^
    |         |
@@ -19,6 +22,9 @@ LL |         XEmpty1() => ()
 error[E0532]: expected tuple struct/variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-pat-2.rs:21:9
    |
+LL | struct Empty1 {}
+   | ---------------- `Empty1` defined here
+...
 LL |         Empty1(..) => ()
    |         ^^^^^^
    |         |
index af8731b5f059633823964fd49e89ca85b18c8cd0..aefdd772b1bfda3f8e382b84592598416b33f3a2 100644 (file)
@@ -1,6 +1,9 @@
 error[E0532]: expected tuple struct/variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:17:9
    |
+LL |     Empty3 {}
+   |     --------- `E::Empty3` defined here
+...
 LL |         E::Empty3() => ()
    |         ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
 
@@ -16,6 +19,9 @@ LL |         XE::XEmpty3() => ()
 error[E0532]: expected tuple struct/variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:25:9
    |
+LL |     Empty3 {}
+   |     --------- `E::Empty3` defined here
+...
 LL |         E::Empty3(..) => ()
    |         ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
 
index 6c15e7bf282cee4ad085c198d2bc0e225fcab59e..4b828c0d942e38f28b9f81847a88fd609ace0a5c 100644 (file)
@@ -19,8 +19,11 @@ LL |         XEmpty6 => ()
 error[E0532]: expected unit struct/variant or constant, found tuple variant `E::Empty4`
   --> $DIR/empty-struct-tuple-pat.rs:29:9
    |
+LL |     Empty4()
+   |     -------- `E::Empty4` defined here
+...
 LL |         E::Empty4 => ()
-   |         ^^^^^^^^^ did you mean `E::Empty4 ( /* fields */ )`?
+   |         ^^^^^^^^^ did you mean `E::Empty4( /* fields */ )`?
 
 error[E0532]: expected unit struct/variant or constant, found tuple variant `XE::XEmpty5`
   --> $DIR/empty-struct-tuple-pat.rs:33:9
@@ -29,7 +32,7 @@ LL |         XE::XEmpty5 => (),
    |         ^^^^-------
    |         |   |
    |         |   help: a unit variant with a similar name exists: `XEmpty4`
-   |         did you mean `XE::XEmpty5 ( /* fields */ )`?
+   |         did you mean `XE::XEmpty5( /* fields */ )`?
 
 error: aborting due to 4 previous errors
 
index ec240003f91822e6eaa23e120aa98e854bf1800f..ce631ca4bf786ec3e2ca69a41ff1b0a5c047d5e4 100644 (file)
@@ -27,6 +27,9 @@ LL |     for _ in (std::ops::Range { start: 0, end: 10 }) {}
 error[E0423]: expected function, found struct `Foo`
   --> $DIR/E0423.rs:4:13
    |
+LL |     struct Foo { a: bool };
+   |     ---------------------- `Foo` defined here
+LL | 
 LL |     let f = Foo();
    |             ^^^
    |             |
diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gates/feature-gate-macros_in_extern.rs
deleted file mode 100644 (file)
index 125af64..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#![feature(decl_macro)]
-
-macro_rules! returns_isize(
-    ($ident:ident) => (
-        fn $ident() -> isize;
-    )
-);
-
-macro takes_u32_returns_u32($ident:ident) {
-    fn $ident (arg: u32) -> u32;
-}
-
-macro_rules! emits_nothing(
-    () => ()
-);
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    returns_isize!(rust_get_test_int);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-    emits_nothing!();
-    //~^ ERROR macro invocations in `extern {}` blocks are experimental
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr
deleted file mode 100644 (file)
index e8b3ab5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/feature-gate-macros_in_extern.rs:19:5
-   |
-LL |     returns_isize!(rust_get_test_int);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/feature-gate-macros_in_extern.rs:21:5
-   |
-LL |     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error[E0658]: macro invocations in `extern {}` blocks are experimental
-  --> $DIR/feature-gate-macros_in_extern.rs:23:5
-   |
-LL |     emits_nothing!();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/49476
-   = help: add `#![feature(macros_in_extern)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index d2b9b90890e3cfb54a6c17382d3b5fb8434457c1..e2229cbc20922caa236d2738e13b6be53136359b 100644 (file)
@@ -1,6 +1,9 @@
 error[E0532]: expected tuple struct/variant, found struct variant `FooB`
   --> $DIR/issue-19086.rs:10:9
    |
+LL |     FooB { x: i32, y: i32 }
+   |     ----------------------- `FooB` defined here
+...
 LL |         FooB(a, b) => println!("{} {}", a, b),
    |         ^^^^ did you mean `FooB { /* fields */ }`?
 
index b56fa949acb7e0a1671b32221be30a87b1a09d2c..e9a5e217392a6e349c7c616e90c50598eb0b4ecf 100644 (file)
@@ -1,11 +1,14 @@
 error[E0532]: expected unit struct/variant or constant, found tuple variant `Foo::Bar`
   --> $DIR/issue-32004.rs:10:9
    |
+LL |     Bar(i32),
+   |     -------- `Foo::Bar` defined here
+...
 LL |         Foo::Bar => {}
    |         ^^^^^---
    |         |    |
    |         |    help: a unit variant with a similar name exists: `Baz`
-   |         did you mean `Foo::Bar ( /* fields */ )`?
+   |         did you mean `Foo::Bar( /* fields */ )`?
 
 error[E0532]: expected tuple struct/variant, found unit struct `S`
   --> $DIR/issue-32004.rs:16:9
index 67acd1d57c27aabdc9b136836222a113181c5ac9..8949c475b6f727e24b839fdb37e0846fa9311051 100644 (file)
@@ -1,12 +1,18 @@
 error[E0532]: expected unit struct/variant or constant, found tuple variant `MyEnum::Tuple`
   --> $DIR/issue-63983.rs:8:9
    |
+LL |     Tuple(i32),
+   |     ---------- `MyEnum::Tuple` defined here
+...
 LL |         MyEnum::Tuple => "",
-   |         ^^^^^^^^^^^^^ did you mean `MyEnum::Tuple ( /* fields */ )`?
+   |         ^^^^^^^^^^^^^ did you mean `MyEnum::Tuple( /* fields */ )`?
 
 error[E0532]: expected unit struct/variant or constant, found struct variant `MyEnum::Struct`
   --> $DIR/issue-63983.rs:10:9
    |
+LL |     Struct{ s: i32 },
+   |     ---------------- `MyEnum::Struct` defined here
+...
 LL |         MyEnum::Struct => "",
    |         ^^^^^^^^^^^^^^ did you mean `MyEnum::Struct { /* fields */ }`?
 
index 1a6b5183f0fae48b735084c400a0b84a951ea3da..6850e999242ea41299030767276a2be3be50ced7 100644 (file)
@@ -29,6 +29,11 @@ fn bar(
         b: i32,
         //~^ ERROR unused variable: `b`
     ) {}
+    fn issue_64682_associated_fn(
+        #[allow(unused_variables)] a: i32,
+        b: i32,
+        //~^ ERROR unused variable: `b`
+    ) {}
 }
 trait RefTrait {
     fn bar(
@@ -37,6 +42,11 @@ fn bar(
         b: i32,
         //~^ ERROR unused variable: `b`
     ) {}
+    fn issue_64682_associated_fn(
+        #[allow(unused_variables)] a: i32,
+        b: i32,
+        //~^ ERROR unused variable: `b`
+    ) {}
 }
 impl RefTrait for RefStruct {
     fn bar(
@@ -45,6 +55,11 @@ fn bar(
         b: i32,
         //~^ ERROR unused variable: `b`
     ) {}
+    fn issue_64682_associated_fn(
+        #[allow(unused_variables)] a: i32,
+        b: i32,
+        //~^ ERROR unused variable: `b`
+    ) {}
 }
 
 fn main() {
index 7ed5669e33c2444adfcf99a423551ad26d50ef18..f8419bf506660480ffe05a40b30c6466c2f71169 100644 (file)
@@ -17,19 +17,25 @@ LL |     b: i32,
    |     ^ help: consider prefixing with an underscore: `_b`
 
 error: unused variable: `a`
-  --> $DIR/lint-unused-variables.rs:53:9
+  --> $DIR/lint-unused-variables.rs:68:9
    |
 LL |         a: i32,
    |         ^ help: consider prefixing with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/lint-unused-variables.rs:59:9
+  --> $DIR/lint-unused-variables.rs:74:9
    |
 LL |         b: i32,
    |         ^ help: consider prefixing with an underscore: `_b`
 
 error: unused variable: `b`
-  --> $DIR/lint-unused-variables.rs:37:9
+  --> $DIR/lint-unused-variables.rs:42:9
+   |
+LL |         b: i32,
+   |         ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `b`
+  --> $DIR/lint-unused-variables.rs:47:9
    |
 LL |         b: i32,
    |         ^ help: consider prefixing with an underscore: `_b`
@@ -47,10 +53,22 @@ LL |         b: i32,
    |         ^ help: consider prefixing with an underscore: `_b`
 
 error: unused variable: `b`
-  --> $DIR/lint-unused-variables.rs:45:9
+  --> $DIR/lint-unused-variables.rs:34:9
+   |
+LL |         b: i32,
+   |         ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `b`
+  --> $DIR/lint-unused-variables.rs:55:9
+   |
+LL |         b: i32,
+   |         ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `b`
+  --> $DIR/lint-unused-variables.rs:60:9
    |
 LL |         b: i32,
    |         ^ help: consider prefixing with an underscore: `_b`
 
-error: aborting due to 8 previous errors
+error: aborting due to 11 previous errors
 
index b45aedb549ecd66d6a5e77437d67e2b2f89d86a9..afdf76b7b580fe27148de3424b699330dec3db5e 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(macros_in_extern)]
-
 macro_rules! m {
     () => {
         let //~ ERROR expected
index b0fafdc3b6326b828474f37791ecc8aa10b69e22..af0ee3ae8eca3a88e173281a1db79af2908d69da 100644 (file)
@@ -1,5 +1,5 @@
 error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found `let`
-  --> $DIR/issue-54441.rs:5:9
+  --> $DIR/issue-54441.rs:3:9
    |
 LL |         let
    |         ^^^ unexpected token
index 34529cdaa64f1bcdfcae36808a8333da8b6888f1..eb2504d4bfdb7ef2024f35fc29127af189eb859a 100644 (file)
@@ -252,12 +252,6 @@ macro_rules! test_path {
 test_path!(std::u8,);
 test_path!(any, super, super::super::self::path, X<Y>::Z<'a, T=U>);
 
-macro_rules! test_meta_block {
-    ($($m:meta)* $b:block) => {};
-}
-
-test_meta_block!(windows {});
-
 macro_rules! test_lifetime {
     (1. $($l:lifetime)* $($b:block)*) => {};
     (2. $($b:block)* $($l:lifetime)*) => {};
diff --git a/src/test/ui/macros/macro-meta-items-modern.rs b/src/test/ui/macros/macro-meta-items-modern.rs
new file mode 100644 (file)
index 0000000..bc6938d
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+macro_rules! check { ($meta:meta) => () }
+
+check!(meta(a b c d));
+check!(meta[a b c d]);
+check!(meta { a b c d });
+check!(meta);
+check!(meta = 0);
+
+fn main() {}
diff --git a/src/test/ui/macros/macros-in-extern-rpass.rs b/src/test/ui/macros/macros-in-extern-rpass.rs
deleted file mode 100644 (file)
index 28abef5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// run-pass
-// ignore-wasm32
-
-#![feature(decl_macro, macros_in_extern)]
-
-macro_rules! returns_isize(
-    ($ident:ident) => (
-        fn $ident() -> isize;
-    )
-);
-
-macro takes_u32_returns_u32($ident:ident) {
-    fn $ident (arg: u32) -> u32;
-}
-
-macro_rules! emits_nothing(
-    () => ()
-);
-
-fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 1isize);
-    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
-}
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    returns_isize!(rust_get_test_int);
-    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
-    emits_nothing!();
-}
diff --git a/src/test/ui/macros/macros-in-extern.rs b/src/test/ui/macros/macros-in-extern.rs
new file mode 100644 (file)
index 0000000..05002ed
--- /dev/null
@@ -0,0 +1,45 @@
+// run-pass
+// ignore-wasm32
+
+#![feature(decl_macro)]
+
+macro_rules! returns_isize(
+    ($ident:ident) => (
+        fn $ident() -> isize;
+    )
+);
+
+macro takes_u32_returns_u32($ident:ident) {
+    fn $ident (arg: u32) -> u32;
+}
+
+macro_rules! emits_nothing(
+    () => ()
+);
+
+macro_rules! emits_multiple(
+    () => {
+        fn f1() -> u32;
+        fn f2() -> u32;
+    }
+);
+
+mod defs {
+    #[no_mangle] extern fn f1() -> u32 { 1 }
+    #[no_mangle] extern fn f2() -> u32 { 2 }
+}
+
+fn main() {
+    assert_eq!(unsafe { rust_get_test_int() }, 1);
+    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
+    assert_eq!(unsafe { f1() }, 1);
+    assert_eq!(unsafe { f2() }, 2);
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern {
+    returns_isize!(rust_get_test_int);
+    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
+    emits_nothing!();
+    emits_multiple!();
+}
index fb1cf7f71e70add8b15b788e9eac2aa8cd04c2e4..21a91f3f32b24fc25d2ef3319b909fef3c9345e6 100644 (file)
@@ -23,4 +23,10 @@ fn main() {
         <Foo>::trait_bar => {}
         //~^ ERROR expected unit struct/variant or constant, found method `<Foo>::trait_bar`
     }
+    if let Foo::bar = 0u32 {}
+    //~^ ERROR expected unit struct/variant or constant, found method `<Foo>::bar`
+    if let <Foo>::bar = 0u32 {}
+    //~^ ERROR expected unit struct/variant or constant, found method `<Foo>::bar`
+    if let Foo::trait_bar = 0u32 {}
+    //~^ ERROR expected unit struct/variant or constant, found method `<Foo>::trait_bar`
 }
index 3f53ad768825b02e81e22b117be88a2507ec5147..257fff4c37dc0055f4c80978dde4f7d8a8768fac 100644 (file)
@@ -16,5 +16,24 @@ error[E0533]: expected unit struct/variant or constant, found method `<Foo>::tra
 LL |         <Foo>::trait_bar => {}
    |         ^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error[E0533]: expected unit struct/variant or constant, found method `<Foo>::bar`
+  --> $DIR/method-path-in-pattern.rs:26:12
+   |
+LL |     if let Foo::bar = 0u32 {}
+   |            ^^^^^^^^
+
+error[E0533]: expected unit struct/variant or constant, found method `<Foo>::bar`
+  --> $DIR/method-path-in-pattern.rs:28:12
+   |
+LL |     if let <Foo>::bar = 0u32 {}
+   |            ^^^^^^^^^^
+
+error[E0533]: expected unit struct/variant or constant, found method `<Foo>::trait_bar`
+  --> $DIR/method-path-in-pattern.rs:30:12
+   |
+LL |     if let Foo::trait_bar = 0u32 {}
+   |            ^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
+For more information about this error, try `rustc --explain E0533`.
index aa21928aaeff28e0d30d93238581e35577e64988..77da07f40d5367fcad9fa1ef27bb6dffc56fb1e5 100644 (file)
@@ -37,6 +37,9 @@ LL | use namespace_mix::xm2::S;
 error[E0423]: expected value, found struct variant `m7::V`
   --> $DIR/namespace-mix.rs:100:11
    |
+LL |         V {},
+   |         ---- `m7::V` defined here
+...
 LL |     check(m7::V);
    |           ^^^^^ did you mean `m7::V { /* fields */ }`?
 help: a tuple variant with a similar name exists
diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.rs
new file mode 100644 (file)
index 0000000..181c770
--- /dev/null
@@ -0,0 +1,15 @@
+// In this regression test we check that a trailing `|` in an or-pattern just
+// before the `if` token of a `match` guard will receive parser recovery with
+// an appropriate error message.
+
+enum E { A, B }
+
+fn main() {
+    match E::A {
+        E::A |
+        E::B | //~ ERROR a trailing `|` is not allowed in an or-pattern
+        if true => {
+            let recovery_witness: bool = 0; //~ ERROR mismatched types
+        }
+    }
+}
diff --git a/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/src/test/ui/or-patterns/issue-64879-trailing-before-guard.stderr
new file mode 100644 (file)
index 0000000..db6670f
--- /dev/null
@@ -0,0 +1,20 @@
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/issue-64879-trailing-before-guard.rs:10:14
+   |
+LL |         E::A |
+   |         ---- while parsing this or-pattern starting here
+LL |         E::B |
+   |              ^ help: remove the `|`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-64879-trailing-before-guard.rs:12:42
+   |
+LL |             let recovery_witness: bool = 0;
+   |                                          ^ expected bool, found integer
+   |
+   = note: expected type `bool`
+              found type `{integer}`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index c61b5cb2082510d26e700dc26060e3adacd4b486..c71c760b1e30374cd2571139f1ec2602f5c96b72 100644 (file)
@@ -2,37 +2,49 @@ error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:8:15
    |
 LL |         1 | 2 || 3 => (),
-   |               ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         |
+   |         while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:13:16
    |
 LL |         (1 | 2 || 3) => (),
-   |                ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          |
+   |          while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:18:16
    |
 LL |         (1 | 2 || 3,) => (),
-   |                ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          |
+   |          while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:25:18
    |
 LL |         TS(1 | 2 || 3) => (),
-   |                  ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |            -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |            |
+   |            while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:32:23
    |
 LL |         NS { f: 1 | 2 || 3 } => (),
-   |                       ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |                 -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |                 |
+   |                 while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:37:16
    |
 LL |         [1 | 2 || 3] => (),
-   |                ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          -     ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |          |
+   |          while parsing this or-pattern starting here
 
 error: unexpected token `||` after pattern
   --> $DIR/multiple-pattern-typo.rs:42:9
index 2a3a6abfb7b624035d189b0ee55e286d86ddd9b1..6d08b47c058ed09ddf32bfadf0a82b795a4b66a5 100644 (file)
@@ -51,24 +51,32 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let ( || A | B) = E::A;
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/or-patterns-syntactic-fail.rs:48:11
    |
 LL |     let [ || A | B ] = [E::A];
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/or-patterns-syntactic-fail.rs:49:13
    |
 LL |     let TS( || A | B );
    |             ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/or-patterns-syntactic-fail.rs:50:17
    |
 LL |     let NS { f: || A | B };
    |                 ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: no rules expected the token `|`
   --> $DIR/or-patterns-syntactic-fail.rs:14:15
index e96d76061ac28913978862002714b2cee1aa53b2..443ef398293d9900a507149595d21e32d334508d 100644 (file)
@@ -1,4 +1,4 @@
-// Test the suggestion to remove a leading `|`.
+// Test the suggestion to remove a leading, or trailing `|`.
 
 // run-rustfix
 
@@ -8,7 +8,7 @@
 fn main() {}
 
 #[cfg(FALSE)]
-fn leading_vert() {
+fn leading() {
     fn fun1(  A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     fn fun2(  A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     let (  A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
@@ -21,3 +21,26 @@ fn leading_vert() {
     let NS { f:  A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
     let NS { f:  A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
 }
+
+#[cfg(FALSE)]
+fn trailing() {
+    let ( A  ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A | B  ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let [ A | B  ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let S { f: B  }; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A | B  ): E; //~ ERROR unexpected token `||` after pattern
+    //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    match A {
+        A  => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A  => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A | B  => {} //~ ERROR unexpected token `||` after pattern
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+        | A | B  => {}
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    }
+
+    let a  : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a  = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a  ; //~ ERROR a trailing `|` is not allowed in an or-pattern
+}
index 3790b17553fe38b8860b18acaa182fd96e408e87..3c427a6f7b23ef9ed7656617e1968d26c70865b1 100644 (file)
@@ -1,4 +1,4 @@
-// Test the suggestion to remove a leading `|`.
+// Test the suggestion to remove a leading, or trailing `|`.
 
 // run-rustfix
 
@@ -8,7 +8,7 @@
 fn main() {}
 
 #[cfg(FALSE)]
-fn leading_vert() {
+fn leading() {
     fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern
     let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern
@@ -21,3 +21,26 @@ fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter patte
     let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
     let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern
 }
+
+#[cfg(FALSE)]
+fn trailing() {
+    let ( A | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let (a |,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A | B | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let [ A | B | ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let S { f: B | }; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let ( A || B | ): E; //~ ERROR unexpected token `||` after pattern
+    //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    match A {
+        A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
+        A || B | => {} //~ ERROR unexpected token `||` after pattern
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+        | A | B | => {}
+        //~^ ERROR a trailing `|` is not allowed in an or-pattern
+    }
+
+    let a | : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a | = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
+    let a | ; //~ ERROR a trailing `|` is not allowed in an or-pattern
+}
index cbe06f997296a476aa2240a095f4530fc442d53b..53025230a63c221d99b7db8b9b874be63cb55a3d 100644 (file)
@@ -9,6 +9,8 @@ error: a leading `|` is not allowed in a parameter pattern
    |
 LL |     fn fun2( || A: E) {}
    |              ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:14:11
@@ -21,6 +23,8 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let ( || A): (E);
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:16:11
@@ -39,6 +43,8 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let [ || A ]: [E; 1];
    |           ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:19:13
@@ -51,6 +57,8 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let TS( || A ): TS;
    |             ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
 
 error: a leading `|` is only allowed in a top-level pattern
   --> $DIR/remove-leading-vert.rs:21:17
@@ -63,6 +71,130 @@ error: a leading `|` is only allowed in a top-level pattern
    |
 LL |     let NS { f: || A }: NS;
    |                 ^^ help: remove the `||`
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:27:13
+   |
+LL |     let ( A | ): E;
+   |           - ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:28:12
+   |
+LL |     let (a |,): (E,);
+   |          - ^ help: remove the `|`
+   |          |
+   |          while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:29:17
+   |
+LL |     let ( A | B | ): E;
+   |           -     ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:30:17
+   |
+LL |     let [ A | B | ]: [E; 1];
+   |           -     ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:31:18
+   |
+LL |     let S { f: B | };
+   |                - ^ help: remove the `|`
+   |                |
+   |                while parsing this or-pattern starting here
+
+error: unexpected token `||` after pattern
+  --> $DIR/remove-leading-vert.rs:32:13
+   |
+LL |     let ( A || B | ): E;
+   |           - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:32:18
+   |
+LL |     let ( A || B | ): E;
+   |           -      ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:35:11
+   |
+LL |         A | => {}
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:36:11
+   |
+LL |         A || => {}
+   |         - ^^ help: remove the `||`
+   |         |
+   |         while parsing this or-pattern starting here
+   |
+   = note: alternatives in or-patterns are separated with `|`, not `||`
+
+error: unexpected token `||` after pattern
+  --> $DIR/remove-leading-vert.rs:37:11
+   |
+LL |         A || B | => {}
+   |         - ^^ help: use a single `|` to separate multiple alternative patterns: `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:37:16
+   |
+LL |         A || B | => {}
+   |         -      ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:39:17
+   |
+LL |         | A | B | => {}
+   |           -     ^ help: remove the `|`
+   |           |
+   |           while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:43:11
+   |
+LL |     let a | : u8 = 0;
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:44:11
+   |
+LL |     let a | = 0;
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
+
+error: a trailing `|` is not allowed in an or-pattern
+  --> $DIR/remove-leading-vert.rs:45:11
+   |
+LL |     let a | ;
+   |         - ^ help: remove the `|`
+   |         |
+   |         while parsing this or-pattern starting here
 
-error: aborting due to 11 previous errors
+error: aborting due to 26 previous errors
 
diff --git a/src/test/ui/panic-runtime/libtest-unwinds.rs b/src/test/ui/panic-runtime/libtest-unwinds.rs
deleted file mode 100644 (file)
index bc13072..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// error-pattern:is not compiled with this crate's panic strategy `abort`
-// compile-flags:-C panic=abort
-// ignore-wasm32-bare compiled with panic=abort by default
-
-#![feature(test)]
-
-extern crate test;
-
-fn main() {
-}
diff --git a/src/test/ui/panic-runtime/libtest-unwinds.stderr b/src/test/ui/panic-runtime/libtest-unwinds.stderr
deleted file mode 100644 (file)
index 704b81a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-error: the linked panic runtime `panic_unwind` is not compiled with this crate's panic strategy `abort`
-
-error: aborting due to previous error
-
index b46d3ca9c233ca2371fe33c3d989f57ca13a72a0..32bb88d31c4c7ccf5a2e43cc32b3062d6f2e8f8f 100644 (file)
@@ -12,6 +12,9 @@ LL |     let x = Enum::Foo(a: 3, b: 4);
 error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo`
   --> $DIR/recover-from-bad-variant.rs:10:9
    |
+LL |     Foo { a: usize, b: usize },
+   |     -------------------------- `Enum::Foo` defined here
+...
 LL |         Enum::Foo(a, b) => {}
    |         ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`?
 
diff --git a/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs b/src/test/ui/proc-macro/auxiliary/test-macros-rpass.rs
deleted file mode 100644 (file)
index 15fe380..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// force-host
-// no-prefer-dynamic
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::TokenStream;
-
-#[proc_macro_attribute]
-pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
-    assert!(_attr.to_string().is_empty());
-    input
-}
-
-#[proc_macro_attribute]
-pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream {
-    assert!(_attr.to_string().is_empty());
-    assert!(!_input.to_string().is_empty());
-    "".parse().unwrap()
-}
-
-#[proc_macro]
-pub fn emit_input(input: TokenStream) -> TokenStream {
-    input
-}
index b7b152e669213beea31d60755375f2ec85034bde..223c4047cb2b1e2548b9dd2fb86fcf23ad00c3a7 100644 (file)
@@ -7,8 +7,6 @@
 // normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
 // normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
 
-#![feature(proc_macro_hygiene)]
-
 #[macro_use]
 extern crate test_macros;
 extern crate dollar_crate_external;
index d0dd1b4603b168b4409fe05738794eeb66c77bc1..5605696715e34223efd00528a90d061e0ad7aad6 100644 (file)
@@ -1,7 +1,5 @@
 // aux-build:lifetimes.rs
 
-#![feature(proc_macro_hygiene)]
-
 extern crate lifetimes;
 
 use lifetimes::*;
index 6e91201405cc69dbc989567ed08f25f02f1d2dd1..10acd4304aa231a9536879065ee6cf631d26d03b 100644 (file)
@@ -1,5 +1,5 @@
 error: expected type, found `'`
-  --> $DIR/lifetimes.rs:9:10
+  --> $DIR/lifetimes.rs:7:10
    |
 LL | type A = single_quote_alone!();
    |          ^^^^^^^^^^^^^^^^^^^^^ this macro call doesn't expand to a type
diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.rs b/src/test/ui/proc-macro/macros-in-extern-derive.rs
new file mode 100644 (file)
index 0000000..d2751a3
--- /dev/null
@@ -0,0 +1,6 @@
+extern {
+    #[derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
+    fn f();
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.stderr b/src/test/ui/proc-macro/macros-in-extern-derive.stderr
new file mode 100644 (file)
index 0000000..e2afb7d
--- /dev/null
@@ -0,0 +1,8 @@
+error: `derive` may only be applied to structs, enums and unions
+  --> $DIR/macros-in-extern-derive.rs:2:5
+   |
+LL |     #[derive(Copy)]
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/proc-macro/macros-in-extern-rpass.rs b/src/test/ui/proc-macro/macros-in-extern-rpass.rs
deleted file mode 100644 (file)
index a30a287..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// run-pass
-// aux-build:test-macros-rpass.rs
-// ignore-wasm32
-
-#![feature(macros_in_extern)]
-
-extern crate test_macros_rpass as test_macros;
-
-use test_macros::{nop_attr, no_output, emit_input};
-
-fn main() {
-    assert_eq!(unsafe { rust_get_test_int() }, 1isize);
-    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
-}
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern {
-    #[no_output]
-    fn some_definitely_unknown_symbol_which_should_be_removed();
-
-    #[nop_attr]
-    fn rust_get_test_int() -> isize;
-
-    emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
-}
diff --git a/src/test/ui/proc-macro/macros-in-extern.rs b/src/test/ui/proc-macro/macros-in-extern.rs
new file mode 100644 (file)
index 0000000..e2b1d55
--- /dev/null
@@ -0,0 +1,22 @@
+// run-pass
+// aux-build:test-macros.rs
+// ignore-wasm32
+
+#[macro_use]
+extern crate test_macros;
+
+fn main() {
+    assert_eq!(unsafe { rust_get_test_int() }, 1);
+    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern {
+    #[empty_attr]
+    fn some_definitely_unknown_symbol_which_should_be_removed();
+
+    #[identity_attr]
+    fn rust_get_test_int() -> isize;
+
+    identity!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
+}
diff --git a/src/test/ui/proc-macro/macros-in-type.rs b/src/test/ui/proc-macro/macros-in-type.rs
new file mode 100644 (file)
index 0000000..19ed58e
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+// aux-build:test-macros.rs
+
+#[macro_use]
+extern crate test_macros;
+
+const C: identity!(u8) = 10;
+
+fn main() {
+    let c: u8 = C;
+}
index 678dc83b753b5f7b5143b846833c62c37698b4d9..0096a84f14c3490a865bcfa723a6082e0ba7bf99 100644 (file)
@@ -50,7 +50,6 @@ fn attrs() {
 }
 
 fn main() {
-    let _x: identity!(u32) = 3; //~ ERROR: procedural macros cannot be expanded to types
     if let identity!(Some(_x)) = Some(3) {}
     //~^ ERROR: procedural macros cannot be expanded to patterns
 
index 8462b564ec1d7b2588458fb52bf209608757fa78..14a4f8c0fbca2ba265b9577fcf15b6a46b48db19 100644 (file)
@@ -94,17 +94,8 @@ LL |     let _x = #[identity_attr] println!();
    = note: for more information, see https://github.com/rust-lang/rust/issues/54727
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
-error[E0658]: procedural macros cannot be expanded to types
-  --> $DIR/proc-macro-gates.rs:53:13
-   |
-LL |     let _x: identity!(u32) = 3;
-   |             ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/54727
-   = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-
 error[E0658]: procedural macros cannot be expanded to patterns
-  --> $DIR/proc-macro-gates.rs:54:12
+  --> $DIR/proc-macro-gates.rs:53:12
    |
 LL |     if let identity!(Some(_x)) = Some(3) {}
    |            ^^^^^^^^^^^^^^^^^^^
@@ -113,7 +104,7 @@ LL |     if let identity!(Some(_x)) = Some(3) {}
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to statements
-  --> $DIR/proc-macro-gates.rs:57:5
+  --> $DIR/proc-macro-gates.rs:56:5
    |
 LL |     empty!(struct S;);
    |     ^^^^^^^^^^^^^^^^^^
@@ -122,7 +113,7 @@ LL |     empty!(struct S;);
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to statements
-  --> $DIR/proc-macro-gates.rs:58:5
+  --> $DIR/proc-macro-gates.rs:57:5
    |
 LL |     empty!(let _x = 3;);
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -131,7 +122,7 @@ LL |     empty!(let _x = 3;);
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to expressions
-  --> $DIR/proc-macro-gates.rs:60:14
+  --> $DIR/proc-macro-gates.rs:59:14
    |
 LL |     let _x = identity!(3);
    |              ^^^^^^^^^^^^
@@ -140,7 +131,7 @@ LL |     let _x = identity!(3);
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
 error[E0658]: procedural macros cannot be expanded to expressions
-  --> $DIR/proc-macro-gates.rs:61:15
+  --> $DIR/proc-macro-gates.rs:60:15
    |
 LL |     let _x = [empty!(3)];
    |               ^^^^^^^^^
@@ -148,6 +139,6 @@ LL |     let _x = [empty!(3)];
    = note: for more information, see https://github.com/rust-lang/rust/issues/54727
    = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index b8d3b744e837c5e16bf5600dd695909ca45a8399..3e8fcdc7ca3e28dd5ce74b5db8f767529dbda3a0 100644 (file)
@@ -15,4 +15,5 @@ LL |         0 ..= <S as Tr>::A::f::<u8> => {}
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0029`.
+Some errors have detailed explanations: E0029, E0533.
+For more information about an error, try `rustc --explain E0029`.
index 293f290f82fd9fe68e2551e5db2e0539a8b3202f..c76e5ef8b3617dddbd083030b8e452d31e4374ef 100644 (file)
@@ -1,6 +1,9 @@
 error[E0423]: expected function, found struct variant `Foo::Variant`
   --> $DIR/issue-18252.rs:6:13
    |
+LL |     Variant { x: usize }
+   |     -------------------- `Foo::Variant` defined here
+...
 LL |     let f = Foo::Variant(42);
    |             ^^^^^^^^^^^^ did you mean `Foo::Variant { /* fields */ }`?
 
index 56a0e397b854c0bc7d4fc688571b6401906e0229..4d20f1580264c6db3f20419fa70179edb146666a 100644 (file)
@@ -1,6 +1,9 @@
 error[E0423]: expected value, found struct variant `Homura::Madoka`
   --> $DIR/issue-19452.rs:10:18
    |
+LL |     Madoka { age: u32 }
+   |     ------------------- `Homura::Madoka` defined here
+...
 LL |     let homura = Homura::Madoka;
    |                  ^^^^^^^^^^^^^^ did you mean `Homura::Madoka { /* fields */ }`?
 
index c97fb4db6be6b8158087dc1fad5491638739f8e3..d9a28e63dce8bda73e8653b06778158d4601ba10 100644 (file)
@@ -1,6 +1,9 @@
 error[E0423]: expected value, found struct `Handle`
   --> $DIR/issue-39226.rs:11:17
    |
+LL | struct Handle {}
+   | ---------------- `Handle` defined here
+...
 LL |         handle: Handle
    |                 ^^^^^^
    |                 |
index 9a46f0d774262ce8f1db5635587509874f7bb156..3fdc7acb274e511433d8e6011c43534adf6cd70c 100644 (file)
@@ -1,8 +1,13 @@
 error[E0423]: expected function, found struct `Monster`
   --> $DIR/issue-6702.rs:7:14
    |
-LL |     let _m = Monster();
-   |              ^^^^^^^ did you mean `Monster { /* fields */ }`?
+LL | / struct Monster {
+LL | |     damage: isize
+LL | | }
+   | |_- `Monster` defined here
+...
+LL |       let _m = Monster();
+   |                ^^^^^^^ did you mean `Monster { /* fields */ }`?
 
 error: aborting due to previous error
 
index 2538bbbf8067f6c4c450f808476224356e2883d4..7d8d1d0abfc210947b51f521207bacf6ca07535f 100644 (file)
@@ -33,8 +33,13 @@ LL |         m::Z::Unit;
 error[E0423]: expected value, found struct variant `Z::Struct`
   --> $DIR/privacy-enum-ctor.rs:29:20
    |
-LL |         let _: Z = Z::Struct;
-   |                    ^^^^^^^^^ did you mean `Z::Struct { /* fields */ }`?
+LL | /             Struct {
+LL | |                 s: u8,
+LL | |             },
+   | |_____________- `Z::Struct` defined here
+...
+LL |           let _: Z = Z::Struct;
+   |                      ^^^^^^^^^ did you mean `Z::Struct { /* fields */ }`?
 
 error[E0423]: expected value, found enum `m::E`
   --> $DIR/privacy-enum-ctor.rs:41:16
@@ -63,8 +68,13 @@ LL | use std::f64::consts::E;
 error[E0423]: expected value, found struct variant `m::E::Struct`
   --> $DIR/privacy-enum-ctor.rs:45:16
    |
-LL |     let _: E = m::E::Struct;
-   |                ^^^^^^^^^^^^ did you mean `m::E::Struct { /* fields */ }`?
+LL | /         Struct {
+LL | |             s: u8,
+LL | |         },
+   | |_________- `m::E::Struct` defined here
+...
+LL |       let _: E = m::E::Struct;
+   |                  ^^^^^^^^^^^^ did you mean `m::E::Struct { /* fields */ }`?
 
 error[E0423]: expected value, found enum `E`
   --> $DIR/privacy-enum-ctor.rs:49:16
@@ -89,8 +99,13 @@ LL | use std::f64::consts::E;
 error[E0423]: expected value, found struct variant `E::Struct`
   --> $DIR/privacy-enum-ctor.rs:53:16
    |
-LL |     let _: E = E::Struct;
-   |                ^^^^^^^^^ did you mean `E::Struct { /* fields */ }`?
+LL | /         Struct {
+LL | |             s: u8,
+LL | |         },
+   | |_________- `E::Struct` defined here
+...
+LL |       let _: E = E::Struct;
+   |                  ^^^^^^^^^ did you mean `E::Struct { /* fields */ }`?
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:57:12
@@ -151,8 +166,13 @@ LL | use m::n::Z;
 error[E0423]: expected value, found struct variant `m::n::Z::Struct`
   --> $DIR/privacy-enum-ctor.rs:64:16
    |
-LL |     let _: Z = m::n::Z::Struct;
-   |                ^^^^^^^^^^^^^^^ did you mean `m::n::Z::Struct { /* fields */ }`?
+LL | /             Struct {
+LL | |                 s: u8,
+LL | |             },
+   | |_____________- `m::n::Z::Struct` defined here
+...
+LL |       let _: Z = m::n::Z::Struct;
+   |                  ^^^^^^^^^^^^^^^ did you mean `m::n::Z::Struct { /* fields */ }`?
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:68:12
index 72d62fe45ce745a5340bc29f7e1d7d67b807b102..979367bc623fd4ec5985136b5c417ab302b6ffdc 100644 (file)
@@ -16,8 +16,13 @@ LL |     S;
 error[E0423]: expected value, found struct `S2`
   --> $DIR/privacy-struct-ctor.rs:38:5
    |
-LL |     S2;
-   |     ^^ did you mean `S2 { /* fields */ }`?
+LL | /     pub struct S2 {
+LL | |         s: u8
+LL | |     }
+   | |_____- `S2` defined here
+...
+LL |       S2;
+   |       ^^ did you mean `S2 { /* fields */ }`?
 
 error[E0423]: expected value, found struct `xcrate::S`
   --> $DIR/privacy-struct-ctor.rs:43:5
diff --git a/src/test/ui/rfc-2565-param-attrs/attr-without-param.rs b/src/test/ui/rfc-2565-param-attrs/attr-without-param.rs
new file mode 100644 (file)
index 0000000..eeb2191
--- /dev/null
@@ -0,0 +1,16 @@
+#[cfg(FALSE)]
+impl S {
+    fn f(#[attr]) {} //~ ERROR expected parameter name, found `)`
+}
+
+#[cfg(FALSE)]
+impl T for S {
+    fn f(#[attr]) {} //~ ERROR expected parameter name, found `)`
+}
+
+#[cfg(FALSE)]
+trait T {
+    fn f(#[attr]); //~ ERROR expected argument name, found `)`
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2565-param-attrs/attr-without-param.stderr b/src/test/ui/rfc-2565-param-attrs/attr-without-param.stderr
new file mode 100644 (file)
index 0000000..26dff4d
--- /dev/null
@@ -0,0 +1,20 @@
+error: expected parameter name, found `)`
+  --> $DIR/attr-without-param.rs:3:17
+   |
+LL |     fn f(#[attr]) {}
+   |                 ^ expected parameter name
+
+error: expected parameter name, found `)`
+  --> $DIR/attr-without-param.rs:8:17
+   |
+LL |     fn f(#[attr]) {}
+   |                 ^ expected parameter name
+
+error: expected argument name, found `)`
+  --> $DIR/attr-without-param.rs:13:17
+   |
+LL |     fn f(#[attr]);
+   |                 ^ expected argument name
+
+error: aborting due to 3 previous errors
+
index 71815e3c08974f3c9b5d2f1205443aa4af91458c..c537c1034b5a6936bb9e834c319a1a212cce46fc 100644 (file)
@@ -11,7 +11,6 @@ macro_rules! checker {
     ($attr_name:ident, $expected:literal) => {
         #[proc_macro_attribute]
         pub fn $attr_name(attr: TokenStream, input: TokenStream) -> TokenStream {
-            assert!(attr.to_string().is_empty());
             assert_eq!(input.to_string(), $expected);
             TokenStream::new()
         }
@@ -28,7 +27,18 @@ pub fn $attr_name(attr: TokenStream, input: TokenStream) -> TokenStream {
 checker!(attr_inherent_2, "fn inherent2(#[a1] &self, #[a2] arg1: u8) { }");
 checker!(attr_inherent_3, "fn inherent3<'a>(#[a1] &'a mut self, #[a2] arg1: u8) { }");
 checker!(attr_inherent_4, "fn inherent4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8) { }");
+checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8) { }");
 checker!(attr_trait_1, "fn trait1(#[a1] self, #[a2] arg1: u8);");
 checker!(attr_trait_2, "fn trait2(#[a1] &self, #[a2] arg1: u8);");
 checker!(attr_trait_3, "fn trait3<'a>(#[a1] &'a mut self, #[a2] arg1: u8);");
 checker!(attr_trait_4, "fn trait4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8, #[a3] Vec<u8>);");
+checker!(attr_trait_issue_64682, "fn trait5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8);");
+checker!(rename_params, r#"impl Foo {
+    fn hello(#[angery(true)] a: i32, #[a2] b: i32, #[what = "how"] c: u32) { }
+    fn hello2(#[a1] #[a2] a: i32, #[what = "how"] b: i32,
+              #[angery(true)] c: u32) {
+    }
+    fn hello_self(#[a1] #[a2] &self, #[a1] #[a2] a: i32,
+                  #[what = "how"] b: i32, #[angery(true)] c: u32) {
+    }
+}"#);
diff --git a/src/test/ui/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs b/src/test/ui/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs
new file mode 100644 (file)
index 0000000..6703039
--- /dev/null
@@ -0,0 +1,21 @@
+// aux-build:param-attrs.rs
+
+// check-pass
+
+extern crate param_attrs;
+
+use param_attrs::rename_params;
+
+#[rename_params(send_help)]
+impl Foo {
+    fn hello(#[angery(true)] a: i32, #[a2] b: i32, #[what = "how"] c: u32) {}
+    fn hello2(#[a1] #[a2] a: i32, #[what = "how"] b: i32, #[angery(true)] c: u32) {}
+    fn hello_self(
+        #[a1] #[a2] &self,
+        #[a1] #[a2] a: i32,
+        #[what = "how"] b: i32,
+        #[angery(true)] c: u32
+    ) {}
+}
+
+fn main() {}
index c4684a3fa82b0f1d0bb419d2bab96c657c74b920..bf09171c9a12afc7914a91341967e18357b2a18f 100644 (file)
@@ -64,6 +64,21 @@ fn foo(
         #[no_mangle] b: i32,
         //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
     ) {}
+
+    fn issue_64682_associated_fn(
+        /// Foo
+        //~^ ERROR documentation comments cannot be applied to function
+        #[test] a: i32,
+        //~^ ERROR expected an inert attribute, found an attribute macro
+        /// Baz
+        //~^ ERROR documentation comments cannot be applied to function
+        #[must_use]
+        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        /// Qux
+        //~^ ERROR documentation comments cannot be applied to function
+        #[no_mangle] b: i32,
+        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+    ) {}
 }
 
 struct RefStruct {}
@@ -104,7 +119,23 @@ fn foo(
         #[no_mangle] b: i32,
         //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
     ) {}
+
+    fn issue_64682_associated_fn(
+        /// Foo
+        //~^ ERROR documentation comments cannot be applied to function
+        #[test] a: i32,
+        //~^ ERROR expected an inert attribute, found an attribute macro
+        /// Baz
+        //~^ ERROR documentation comments cannot be applied to function
+        #[must_use]
+        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+        /// Qux
+        //~^ ERROR documentation comments cannot be applied to function
+        #[no_mangle] b: i32,
+        //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+    ) {}
 }
+
 impl RefTrait for RefStruct {
     fn foo(
         /// Foo
index 0fc6ca2f7f37ae8fd133a20bdb6f49e847c5e5f5..4d0349e8765f0eca73372ae915c8d11e41ca3671 100644 (file)
@@ -23,25 +23,37 @@ LL |         #[test] a: i32,
    |         ^^^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:77:9
+  --> $DIR/param-attrs-builtin-attrs.rs:71:9
    |
 LL |         #[test] a: i32,
    |         ^^^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:96:9
+  --> $DIR/param-attrs-builtin-attrs.rs:92:9
    |
 LL |         #[test] a: i32,
    |         ^^^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:115:9
+  --> $DIR/param-attrs-builtin-attrs.rs:111:9
    |
 LL |         #[test] a: i32,
    |         ^^^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/param-attrs-builtin-attrs.rs:132:9
+  --> $DIR/param-attrs-builtin-attrs.rs:126:9
+   |
+LL |         #[test] a: i32,
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:146:9
+   |
+LL |         #[test] a: i32,
+   |         ^^^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/param-attrs-builtin-attrs.rs:163:9
    |
 LL |         #[test] a: u32,
    |         ^^^^^^^
@@ -173,142 +185,202 @@ LL |         #[no_mangle] b: i32,
    |         ^^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:72:9
+  --> $DIR/param-attrs-builtin-attrs.rs:69:9
    |
 LL |         /// Foo
    |         ^^^^^^^ doc comments are not allowed here
 
 error: documentation comments cannot be applied to function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:73:9
+   |
+LL |         /// Baz
+   |         ^^^^^^^ doc comments are not allowed here
+
+error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
   --> $DIR/param-attrs-builtin-attrs.rs:75:9
    |
+LL |         #[must_use]
+   |         ^^^^^^^^^^^
+
+error: documentation comments cannot be applied to function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:77:9
+   |
+LL |         /// Qux
+   |         ^^^^^^^ doc comments are not allowed here
+
+error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:79:9
+   |
+LL |         #[no_mangle] b: i32,
+   |         ^^^^^^^^^^^^
+
+error: documentation comments cannot be applied to function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:87:9
+   |
+LL |         /// Foo
+   |         ^^^^^^^ doc comments are not allowed here
+
+error: documentation comments cannot be applied to function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:90:9
+   |
 LL |         /// Bar
    |         ^^^^^^^ doc comments are not allowed here
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:79:9
+  --> $DIR/param-attrs-builtin-attrs.rs:94:9
    |
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:81:9
+  --> $DIR/param-attrs-builtin-attrs.rs:96:9
    |
 LL |         #[must_use]
    |         ^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:83:9
+  --> $DIR/param-attrs-builtin-attrs.rs:98:9
    |
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:85:9
+  --> $DIR/param-attrs-builtin-attrs.rs:100:9
    |
 LL |         #[no_mangle] b: i32,
    |         ^^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:91:9
+  --> $DIR/param-attrs-builtin-attrs.rs:106:9
    |
 LL |         /// Foo
    |         ^^^^^^^ doc comments are not allowed here
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:94:9
+  --> $DIR/param-attrs-builtin-attrs.rs:109:9
    |
 LL |         /// Bar
    |         ^^^^^^^ doc comments are not allowed here
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:98:9
+  --> $DIR/param-attrs-builtin-attrs.rs:113:9
    |
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:100:9
+  --> $DIR/param-attrs-builtin-attrs.rs:115:9
    |
 LL |         #[must_use]
    |         ^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:102:9
+  --> $DIR/param-attrs-builtin-attrs.rs:117:9
    |
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:104:9
+  --> $DIR/param-attrs-builtin-attrs.rs:119:9
    |
 LL |         #[no_mangle] b: i32,
    |         ^^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:110:9
+  --> $DIR/param-attrs-builtin-attrs.rs:124:9
    |
 LL |         /// Foo
    |         ^^^^^^^ doc comments are not allowed here
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:113:9
+  --> $DIR/param-attrs-builtin-attrs.rs:128:9
+   |
+LL |         /// Baz
+   |         ^^^^^^^ doc comments are not allowed here
+
+error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:130:9
+   |
+LL |         #[must_use]
+   |         ^^^^^^^^^^^
+
+error: documentation comments cannot be applied to function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:132:9
+   |
+LL |         /// Qux
+   |         ^^^^^^^ doc comments are not allowed here
+
+error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:134:9
+   |
+LL |         #[no_mangle] b: i32,
+   |         ^^^^^^^^^^^^
+
+error: documentation comments cannot be applied to function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:141:9
+   |
+LL |         /// Foo
+   |         ^^^^^^^ doc comments are not allowed here
+
+error: documentation comments cannot be applied to function parameters
+  --> $DIR/param-attrs-builtin-attrs.rs:144:9
    |
 LL |         /// Bar
    |         ^^^^^^^ doc comments are not allowed here
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:117:9
+  --> $DIR/param-attrs-builtin-attrs.rs:148:9
    |
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:119:9
+  --> $DIR/param-attrs-builtin-attrs.rs:150:9
    |
 LL |         #[must_use]
    |         ^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:121:9
+  --> $DIR/param-attrs-builtin-attrs.rs:152:9
    |
 LL |         /// Qux
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:123:9
+  --> $DIR/param-attrs-builtin-attrs.rs:154:9
    |
 LL |         #[no_mangle] b: i32,
    |         ^^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:130:9
+  --> $DIR/param-attrs-builtin-attrs.rs:161:9
    |
 LL |         /// Foo
    |         ^^^^^^^ doc comments are not allowed here
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:134:9
+  --> $DIR/param-attrs-builtin-attrs.rs:165:9
    |
 LL |         /// Bar
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:136:9
+  --> $DIR/param-attrs-builtin-attrs.rs:167:9
    |
 LL |         #[must_use]
    |         ^^^^^^^^^^^
 
 error: documentation comments cannot be applied to function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:138:9
+  --> $DIR/param-attrs-builtin-attrs.rs:169:9
    |
 LL |         /// Baz
    |         ^^^^^^^ doc comments are not allowed here
 
 error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/param-attrs-builtin-attrs.rs:140:9
+  --> $DIR/param-attrs-builtin-attrs.rs:171:9
    |
 LL |         #[no_mangle] b: i32
    |         ^^^^^^^^^^^^
 
-error: aborting due to 52 previous errors
+error: aborting due to 64 previous errors
 
index d44ff14e992474e64ac0e1f077e93b3d7f00a166..a4d9d32b514ac211d90d7c99414370713dd52372 100644 (file)
@@ -51,6 +51,14 @@ fn bar(
         //~^ ERROR unused variable: `c`
         #[cfg_attr(something, cfg(nothing))] d: i32,
     ) {}
+    fn issue_64682_associated_fn(
+        #[cfg(nothing)] a: i32,
+        #[cfg(something)] b: i32,
+        //~^ ERROR unused variable: `b`
+        #[cfg_attr(nothing, cfg(nothing))] c: i32,
+        //~^ ERROR unused variable: `c`
+        #[cfg_attr(something, cfg(nothing))] d: i32,
+    ) {}
 }
 trait RefTrait {
     fn bar(
@@ -62,6 +70,14 @@ fn bar(
         //~^ ERROR unused variable: `c`
         #[cfg_attr(something, cfg(nothing))] d: i32,
     ) {}
+    fn issue_64682_associated_fn(
+        #[cfg(nothing)] a: i32,
+        #[cfg(something)] b: i32,
+        //~^ ERROR unused variable: `b`
+        #[cfg_attr(nothing, cfg(nothing))] c: i32,
+        //~^ ERROR unused variable: `c`
+        #[cfg_attr(something, cfg(nothing))] d: i32,
+    ) {}
 }
 impl RefTrait for RefStruct {
     fn bar(
@@ -73,6 +89,14 @@ fn bar(
         //~^ ERROR unused variable: `c`
         #[cfg_attr(something, cfg(nothing))] d: i32,
     ) {}
+    fn issue_64682_associated_fn(
+        #[cfg(nothing)] a: i32,
+        #[cfg(something)] b: i32,
+        //~^ ERROR unused variable: `b`
+        #[cfg_attr(nothing, cfg(nothing))] c: i32,
+        //~^ ERROR unused variable: `c`
+        #[cfg_attr(something, cfg(nothing))] d: i32,
+    ) {}
 }
 
 fn main() {
index 3232e2a0411a270335498e05ce185bd753808c91..8d9571d09a856228c2e884efcb5588595b116c80 100644 (file)
@@ -23,31 +23,43 @@ LL |     #[cfg_attr(nothing, cfg(nothing))] c: i32,
    |                                        ^ help: consider prefixing with an underscore: `_c`
 
 error: unused variable: `a`
-  --> $DIR/param-attrs-cfg.rs:83:27
+  --> $DIR/param-attrs-cfg.rs:107:27
    |
 LL |         #[cfg(something)] a: i32,
    |                           ^ help: consider prefixing with an underscore: `_a`
 
 error: unused variable: `b`
-  --> $DIR/param-attrs-cfg.rs:89:27
+  --> $DIR/param-attrs-cfg.rs:113:27
    |
 LL |         #[cfg(something)] b: i32,
    |                           ^ help: consider prefixing with an underscore: `_b`
 
 error: unused variable: `c`
-  --> $DIR/param-attrs-cfg.rs:91:44
+  --> $DIR/param-attrs-cfg.rs:115:44
    |
 LL |         #[cfg_attr(nothing, cfg(nothing))] c: i32,
    |                                            ^ help: consider prefixing with an underscore: `_c`
 
 error: unused variable: `b`
-  --> $DIR/param-attrs-cfg.rs:59:27
+  --> $DIR/param-attrs-cfg.rs:67:27
    |
 LL |         #[cfg(something)] b: i32,
    |                           ^ help: consider prefixing with an underscore: `_b`
 
 error: unused variable: `c`
-  --> $DIR/param-attrs-cfg.rs:61:44
+  --> $DIR/param-attrs-cfg.rs:69:44
+   |
+LL |         #[cfg_attr(nothing, cfg(nothing))] c: i32,
+   |                                            ^ help: consider prefixing with an underscore: `_c`
+
+error: unused variable: `b`
+  --> $DIR/param-attrs-cfg.rs:75:27
+   |
+LL |         #[cfg(something)] b: i32,
+   |                           ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `c`
+  --> $DIR/param-attrs-cfg.rs:77:44
    |
 LL |         #[cfg_attr(nothing, cfg(nothing))] c: i32,
    |                                            ^ help: consider prefixing with an underscore: `_c`
@@ -71,16 +83,40 @@ LL |         #[cfg_attr(nothing, cfg(nothing))] c: i32,
    |                                            ^ help: consider prefixing with an underscore: `_c`
 
 error: unused variable: `b`
-  --> $DIR/param-attrs-cfg.rs:70:27
+  --> $DIR/param-attrs-cfg.rs:56:27
+   |
+LL |         #[cfg(something)] b: i32,
+   |                           ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `c`
+  --> $DIR/param-attrs-cfg.rs:58:44
+   |
+LL |         #[cfg_attr(nothing, cfg(nothing))] c: i32,
+   |                                            ^ help: consider prefixing with an underscore: `_c`
+
+error: unused variable: `b`
+  --> $DIR/param-attrs-cfg.rs:86:27
+   |
+LL |         #[cfg(something)] b: i32,
+   |                           ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `c`
+  --> $DIR/param-attrs-cfg.rs:88:44
+   |
+LL |         #[cfg_attr(nothing, cfg(nothing))] c: i32,
+   |                                            ^ help: consider prefixing with an underscore: `_c`
+
+error: unused variable: `b`
+  --> $DIR/param-attrs-cfg.rs:94:27
    |
 LL |         #[cfg(something)] b: i32,
    |                           ^ help: consider prefixing with an underscore: `_b`
 
 error: unused variable: `c`
-  --> $DIR/param-attrs-cfg.rs:72:44
+  --> $DIR/param-attrs-cfg.rs:96:44
    |
 LL |         #[cfg_attr(nothing, cfg(nothing))] c: i32,
    |                                            ^ help: consider prefixing with an underscore: `_c`
 
-error: aborting due to 13 previous errors
+error: aborting due to 19 previous errors
 
index fb86020d992e96c64376bf44ed5337d1e8edac5f..1183ac65b9a7fab5879afd6ef3da25e01387f935 100644 (file)
@@ -36,6 +36,9 @@ fn inherent3<'a>(#[a1] &'a mut self, #[a2] arg1: u8) {}
 
     #[attr_inherent_4]
     fn inherent4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8) {}
+
+    #[attr_inherent_issue_64682]
+    fn inherent5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8) {}
 }
 
 trait A {
@@ -50,6 +53,9 @@ trait A {
 
     #[attr_trait_4]
     fn trait4<'a>(#[a1] self: Box<Self>, #[a2] arg1: u8, #[a3] Vec<u8>);
+
+    #[attr_trait_issue_64682]
+    fn trait5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8);
 }
 
 fn main() {}
index e2680446f851a891664e1b3631864707372f67c8..be9085d5878cb493d3860b98a00a5f972e680332 100644 (file)
@@ -38,6 +38,9 @@ fn inherent3<'a>(#[id] &'a mut self, #[id] arg1: u8) {}
     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
     //~^ ERROR expected an inert attribute, found an attribute macro
     //~| ERROR expected an inert attribute, found an attribute macro
+    fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
 }
 
 trait A {
@@ -54,6 +57,9 @@ trait A {
     //~^ ERROR expected an inert attribute, found an attribute macro
     //~| ERROR expected an inert attribute, found an attribute macro
     //~| ERROR expected an inert attribute, found an attribute macro
+    fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
+    //~^ ERROR expected an inert attribute, found an attribute macro
+    //~| ERROR expected an inert attribute, found an attribute macro
 }
 
 fn main() {}
index 4654dc1b496f2c8801bc3196eb111174001e72fc..1cc3c3d82281bb1579c2442dd996f0de20ce5904 100644 (file)
@@ -95,58 +95,82 @@ LL |     fn inherent4<'a>(#[id] self: Box<Self>, #[id] arg1: u8) {}
    |                                             ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:44:15
+  --> $DIR/proc-macro-cannot-be-used.rs:41:38
+   |
+LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
+   |                                      ^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/proc-macro-cannot-be-used.rs:41:54
+   |
+LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8) {}
+   |                                                      ^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/proc-macro-cannot-be-used.rs:47:15
    |
 LL |     fn trait1(#[id] self, #[id] arg1: u8);
    |               ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:44:27
+  --> $DIR/proc-macro-cannot-be-used.rs:47:27
    |
 LL |     fn trait1(#[id] self, #[id] arg1: u8);
    |                           ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:47:15
+  --> $DIR/proc-macro-cannot-be-used.rs:50:15
    |
 LL |     fn trait2(#[id] &self, #[id] arg1: u8);
    |               ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:47:28
+  --> $DIR/proc-macro-cannot-be-used.rs:50:28
    |
 LL |     fn trait2(#[id] &self, #[id] arg1: u8);
    |                            ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:50:19
+  --> $DIR/proc-macro-cannot-be-used.rs:53:19
    |
 LL |     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
    |                   ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:50:39
+  --> $DIR/proc-macro-cannot-be-used.rs:53:39
    |
 LL |     fn trait3<'a>(#[id] &'a mut self, #[id] arg1: u8);
    |                                       ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:53:19
+  --> $DIR/proc-macro-cannot-be-used.rs:56:19
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
    |                   ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:53:42
+  --> $DIR/proc-macro-cannot-be-used.rs:56:42
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
    |                                          ^^^^^
 
 error: expected an inert attribute, found an attribute macro
-  --> $DIR/proc-macro-cannot-be-used.rs:53:58
+  --> $DIR/proc-macro-cannot-be-used.rs:56:58
    |
 LL |     fn trait4<'a>(#[id] self: Box<Self>, #[id] arg1: u8, #[id] Vec<u8>);
    |                                                          ^^^^^
 
-error: aborting due to 25 previous errors
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/proc-macro-cannot-be-used.rs:60:38
+   |
+LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
+   |                                      ^^^^^
+
+error: expected an inert attribute, found an attribute macro
+  --> $DIR/proc-macro-cannot-be-used.rs:60:54
+   |
+LL |     fn issue_64682_associated_fn<'a>(#[id] arg1: u8, #[id] arg2: u8);
+   |                                                      ^^^^^
+
+error: aborting due to 29 previous errors
 
index 7e164ba9681c6cf839d0550e07ec969dc30849aa..d05e89e257f459fc293a73ba9b6d536e97c56240 100644 (file)
@@ -6,3 +6,4 @@ LL | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0493`.
index 8a23dad1ba3ea36c3f8da5ea2fe45671ffda0833..bc08f33f8209371b7cf1af73fe34a199e5ef4fe0 100644 (file)
@@ -68,4 +68,5 @@ LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1;
 
 error: aborting due to 10 previous errors
 
-For more information about this error, try `rustc --explain E0716`.
+Some errors have detailed explanations: E0493, E0716.
+For more information about an error, try `rustc --explain E0493`.
index 85cbc787bc2db5b50e5156a3d4dd075572afb02a..a52ec6dc539386a0fd67c47105196a496bfff1f3 100644 (file)
@@ -50,7 +50,10 @@ error[E0308]: mismatched types
   --> $DIR/struct-literal-variant-in-if.rs:10:20
    |
 LL |     if x == E::V { field } {}
-   |                    ^^^^^ expected (), found bool
+   |     ---------------^^^^^--- help: consider using a semicolon here
+   |     |              |
+   |     |              expected (), found bool
+   |     expected this to be `()`
    |
    = note: expected type `()`
               found type `bool`
index 28b331bdbdcbc468e69b48cd50845d93993e9295..1af0f7a191e80d1056b787436c7a45ec71d92c42 100644 (file)
@@ -1,6 +1,9 @@
 error[E0423]: expected value, found struct variant `E::B`
   --> $DIR/fn-or-tuple-struct-without-args.rs:36:16
    |
+LL |     B { a: usize },
+   |     -------------- `E::B` defined here
+...
 LL |     let _: E = E::B;
    |                ^^^-
    |                |  |
index 6d7d98ac6a16bf64de285d90073f4a563e5239db..fbcfba6653f274bf3e1a7d2873420f54d78267c4 100644 (file)
@@ -1,6 +1,9 @@
 error[E0423]: expected value, found struct `X`
   --> $DIR/issue-61226.rs:3:10
    |
+LL | struct X {}
+   | ----------- `X` defined here
+LL | fn main() {
 LL |     vec![X]; //…
    |          ^ did you mean `X { /* fields */ }`?
 
diff --git a/src/test/ui/suggestions/match-needing-semi.fixed b/src/test/ui/suggestions/match-needing-semi.fixed
new file mode 100644 (file)
index 0000000..03cbed1
--- /dev/null
@@ -0,0 +1,18 @@
+// check-only
+// run-rustfix
+
+fn main() {
+    match 3 {
+        4 => 1,
+        3 => {
+            2 //~ ERROR mismatched types
+        }
+        _ => 2
+    };
+    match 3 { //~ ERROR mismatched types
+        4 => 1,
+        3 => 2,
+        _ => 2
+    };
+    let _ = ();
+}
diff --git a/src/test/ui/suggestions/match-needing-semi.rs b/src/test/ui/suggestions/match-needing-semi.rs
new file mode 100644 (file)
index 0000000..f34071a
--- /dev/null
@@ -0,0 +1,18 @@
+// check-only
+// run-rustfix
+
+fn main() {
+    match 3 {
+        4 => 1,
+        3 => {
+            2 //~ ERROR mismatched types
+        }
+        _ => 2
+    }
+    match 3 { //~ ERROR mismatched types
+        4 => 1,
+        3 => 2,
+        _ => 2
+    }
+    let _ = ();
+}
diff --git a/src/test/ui/suggestions/match-needing-semi.stderr b/src/test/ui/suggestions/match-needing-semi.stderr
new file mode 100644 (file)
index 0000000..9889458
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0308]: mismatched types
+  --> $DIR/match-needing-semi.rs:8:13
+   |
+LL | /     match 3 {
+LL | |         4 => 1,
+LL | |         3 => {
+LL | |             2
+   | |             ^ expected (), found integer
+LL | |         }
+LL | |         _ => 2
+LL | |     }
+   | |     -- help: consider using a semicolon here
+   | |_____|
+   |       expected this to be `()`
+   |
+   = note: expected type `()`
+              found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/match-needing-semi.rs:12:5
+   |
+LL | /     match 3 {
+LL | |         4 => 1,
+LL | |         3 => 2,
+LL | |         _ => 2
+LL | |     }
+   | |     ^- help: consider using a semicolon here
+   | |_____|
+   |       expected (), found integer
+   |
+   = note: expected type `()`
+              found type `{integer}`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/test-panic-abort-disabled.rs b/src/test/ui/test-panic-abort-disabled.rs
new file mode 100644 (file)
index 0000000..f24046f
--- /dev/null
@@ -0,0 +1,20 @@
+// error-pattern:building tests with panic=abort is not yet supported
+// no-prefer-dynamic
+// compile-flags: --test -Cpanic=abort
+// run-flags: --test-threads=1
+
+// ignore-wasm no panic or subprocess support
+// ignore-emscripten no panic or subprocess support
+
+#![cfg(test)]
+
+#[test]
+fn it_works() {
+    assert_eq!(1 + 1, 2);
+}
+
+#[test]
+#[should_panic]
+fn it_panics() {
+    assert_eq!(1 + 1, 4);
+}
diff --git a/src/test/ui/test-panic-abort-disabled.stderr b/src/test/ui/test-panic-abort-disabled.stderr
new file mode 100644 (file)
index 0000000..a8d9bad
--- /dev/null
@@ -0,0 +1,4 @@
+error: building tests with panic=abort is not yet supported
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/test-panic-abort.rs b/src/test/ui/test-panic-abort.rs
new file mode 100644 (file)
index 0000000..415ecbf
--- /dev/null
@@ -0,0 +1,36 @@
+// no-prefer-dynamic
+// compile-flags: --test -Cpanic=abort -Zpanic_abort_tests
+// run-flags: --test-threads=1
+// run-fail
+// check-run-results
+
+// ignore-wasm no panic or subprocess support
+// ignore-emscripten no panic or subprocess support
+
+#![cfg(test)]
+
+use std::io::Write;
+
+#[test]
+fn it_works() {
+    assert_eq!(1 + 1, 2);
+}
+
+#[test]
+#[should_panic]
+fn it_panics() {
+    assert_eq!(1 + 1, 4);
+}
+
+#[test]
+fn it_fails() {
+    println!("hello, world");
+    writeln!(std::io::stdout(), "testing123").unwrap();
+    writeln!(std::io::stderr(), "testing321").unwrap();
+    assert_eq!(1 + 1, 5);
+}
+
+#[test]
+fn it_exits() {
+    std::process::exit(123);
+}
diff --git a/src/test/ui/test-panic-abort.run.stdout b/src/test/ui/test-panic-abort.run.stdout
new file mode 100644 (file)
index 0000000..32c96b4
--- /dev/null
@@ -0,0 +1,29 @@
+
+running 4 tests
+test it_exits ... FAILED
+test it_fails ... FAILED
+test it_panics ... ok
+test it_works ... ok
+
+failures:
+
+---- it_exits stdout ----
+---- it_exits stderr ----
+note: got unexpected return code 123
+---- it_fails stdout ----
+hello, world
+testing123
+---- it_fails stderr ----
+testing321
+thread 'main' panicked at 'assertion failed: `(left == right)`
+  left: `2`,
+ right: `5`', $DIR/test-panic-abort.rs:30:5
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
+
+
+failures:
+    it_exits
+    it_fails
+
+test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out
+
index 128a85e15634cd44c5985cb9ea887e7eae5c05cc..357b33de51b84e53b9f17baa8effccb7cbfd7c91 100644 (file)
@@ -6,3 +6,4 @@ LL |             Self::A => (),
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0533`.
index c1ea816b7facf7bca12a0e0146323a924890a273..c6528e417d8aecdacca3850c197d473f5e834c79 100644 (file)
@@ -39,5 +39,5 @@ LL |     let Alias::Unit() = panic!();
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0164, E0618.
+Some errors have detailed explanations: E0164, E0533, E0618.
 For more information about an error, try `rustc --explain E0164`.
index edb9eb7d860e2da24a80125063b49056c29a3c3c..2358a065d62d1359d8b08ab67d4fc86fb06a9d83 100644 (file)
@@ -100,6 +100,7 @@ pub enum PassMode {
     Check,
     Build,
     Run,
+    RunFail,
 }
 
 impl FromStr for PassMode {
@@ -120,6 +121,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             PassMode::Check => "check",
             PassMode::Build => "build",
             PassMode::Run => "run",
+            PassMode::RunFail => "run-fail",
         };
         fmt::Display::fmt(s, f)
     }
index 48dd68d0f61eededa6001b1b640ff1cc1a179a9e..df56448dd225df39686f1ef541cb395776f8ee5d 100644 (file)
@@ -610,6 +610,11 @@ fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config
                 panic!("`run-pass` header is only supported in UI tests")
             }
             Some(PassMode::Run)
+        } else if config.parse_name_directive(ln, "run-fail") {
+            if config.mode != Mode::Ui {
+                panic!("`run-fail` header is only supported in UI tests")
+            }
+            Some(PassMode::RunFail)
         } else {
             None
         };
index baed27dd15152712c542b841fe16029c3c197cd2..ea31f37c7a52b7c44a756d088a9c288b39f481d2 100644 (file)
@@ -326,6 +326,14 @@ fn pass_mode(&self) -> Option<PassMode> {
         self.props.pass_mode(self.config)
     }
 
+    fn should_run(&self) -> bool {
+        let pass_mode = self.pass_mode();
+        match self.config.mode {
+            Ui => pass_mode == Some(PassMode::Run) || pass_mode == Some(PassMode::RunFail),
+            mode => panic!("unimplemented for mode {:?}", mode),
+        }
+    }
+
     fn should_run_successfully(&self) -> bool {
         let pass_mode = self.pass_mode();
         match self.config.mode {
@@ -1534,7 +1542,7 @@ fn is_unexpected_compiler_message(
     fn compile_test(&self) -> ProcRes {
         // Only use `make_exe_name` when the test ends up being executed.
         let will_execute = match self.config.mode {
-            Ui => self.should_run_successfully(),
+            Ui => self.should_run(),
             Incremental => self.revision.unwrap().starts_with("r"),
             RunFail | RunPassValgrind | MirOpt |
             DebugInfoCdb | DebugInfoGdbLldb | DebugInfoGdb | DebugInfoLldb => true,
@@ -3107,7 +3115,7 @@ fn run_ui_test(&self) {
 
         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
 
-        if self.should_run_successfully() {
+        if self.should_run() {
             let proc_res = self.exec_compiled_test();
             let run_output_errors = if self.props.check_run_results {
                 self.load_compare_outputs(&proc_res, TestOutput::Run, explicit)
@@ -3120,8 +3128,14 @@ fn run_ui_test(&self) {
                     &proc_res,
                 );
             }
-            if !proc_res.status.success() {
-                self.fatal_proc_rec("test run failed!", &proc_res);
+            if self.should_run_successfully() {
+                if !proc_res.status.success() {
+                    self.fatal_proc_rec("test run failed!", &proc_res);
+                }
+            } else {
+                if proc_res.status.success() {
+                    self.fatal_proc_rec("test run succeeded!", &proc_res);
+                }
             }
         }
 
index 130f9488d3b861e02c9282b686eec717e30912cf..07ac10277ea5ad42efbb914da5844e0ab08efbf4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 130f9488d3b861e02c9282b686eec717e30912cf
+Subproject commit 07ac10277ea5ad42efbb914da5844e0ab08efbf4